Android實現(xiàn)垂直進度條VerticalSeekBar
本文實例為大家分享了Android實現(xiàn)垂直進度條的具體代碼,供大家參考,具體內(nèi)容如下
水平的進度條見多了,總會想見個垂直的進度條開開眼。今天咱就試試。
要說原理也簡單,就是把寬高倒置,其他的理論上都不需要動,發(fā)現(xiàn)問題再補補也就行了。
官方提供
官方是提供了垂直進度條的例子源碼的,位置在android-sdk-windows\sources\android-23\com\android\example\rscamera\VerticalSeekBar.java,當(dāng)然首先你SDK中要有Android 6.0。
VerticalSeekBar.java
/**
* Class to create a vertical slider
*/
public class VerticalSeekBar extends SeekBar {
public VerticalSeekBar(Context context) {
super(context);
}
public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public VerticalSeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
protected void onDraw(Canvas c) {
c.rotate(-90);
c.translate(-getHeight(), 0);
super.onDraw(c);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
setProgress(getMax() - (int) (getMax() * event.getY() / getHeight()));
onSizeChanged(getWidth(), getHeight(), 0, 0);
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
}
繼承SeekBar是最簡單快捷的,不用重寫太多方法,只需要把
onMeasure
onSizeChanged
onDraw
三個方法作一些改動;但也有一些問題,比如只能響應(yīng)onPregress方法,為了讓他能響應(yīng)onStartTrackingTouch和onStopTrackingTouch方法,只好再加一些代碼,于是有了改進版。
稍作改進
VerticalSeekBar2.java
public class VerticalSeekBar2 extends SeekBar {
private Drawable mThumb;
private OnSeekBarChangeListener mOnSeekBarChangeListener;
public VerticalSeekBar2(Context context) {
super(context);
}
public VerticalSeekBar2(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VerticalSeekBar2(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setOnSeekBarChangeListener(OnSeekBarChangeListener l) {
mOnSeekBarChangeListener = l;
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
protected void onDraw(Canvas c) {
c.rotate(-90);
c.translate(-getHeight(), 0);
super.onDraw(c);
}
void onProgressRefresh(float scale, boolean fromUser) {
Drawable thumb = mThumb;
if (thumb != null) {
setThumbPos(getHeight(), thumb, scale, Integer.MIN_VALUE);
invalidate();
}
if (mOnSeekBarChangeListener != null) {
mOnSeekBarChangeListener.onProgressChanged(this, getProgress(), fromUser);
}
}
private void setThumbPos(int w, Drawable thumb, float scale, int gap) {
int available = w - getPaddingLeft() - getPaddingRight();
int thumbWidth = thumb.getIntrinsicWidth();
int thumbHeight = thumb.getIntrinsicHeight();
int thumbPos = (int) (scale * available + 0.5f);
// int topBound = getWidth() / 2 - thumbHeight / 2 - getPaddingTop();
// int bottomBound = getWidth() / 2 + thumbHeight / 2 - getPaddingTop();
int topBound, bottomBound;
if (gap == Integer.MIN_VALUE) {
Rect oldBounds = thumb.getBounds();
topBound = oldBounds.top;
bottomBound = oldBounds.bottom;
} else {
topBound = gap;
bottomBound = gap + thumbHeight;
}
thumb.setBounds(thumbPos, topBound, thumbPos + thumbWidth, bottomBound);
}
public void setThumb(Drawable thumb) {
mThumb = thumb;
super.setThumb(thumb);
}
void onStartTrackingTouch() {
if (mOnSeekBarChangeListener != null) {
mOnSeekBarChangeListener.onStartTrackingTouch(this);
}
}
void onStopTrackingTouch() {
if (mOnSeekBarChangeListener != null) {
mOnSeekBarChangeListener.onStopTrackingTouch(this);
}
}
private void attemptClaimDrag() {
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(true);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
setPressed(true);
onStartTrackingTouch();
break;
case MotionEvent.ACTION_MOVE:
attemptClaimDrag();
setProgress(getMax() - (int) (getMax() * event.getY() / getHeight()));
break;
case MotionEvent.ACTION_UP:
onStopTrackingTouch();
setPressed(false);
break;
case MotionEvent.ACTION_CANCEL:
onStopTrackingTouch();
setPressed(false);
break;
}
return true;
}
為了響應(yīng)另外兩個不知道怎么就被onPregress拋棄的方法,添了這么多代碼真是罪過,不過都是從SeekBar的父類AbsSeekBar中仿寫過來的,邏輯稍作改動就能用。
對比測試
上圖。

左邊是官方例子中的,右邊是改進過的。
測試源碼:垂直進度條VerticalSeekBar
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android 仿摩拜單車共享單車進度條實現(xiàn)StepView效果
這篇文章主要介紹了android 仿摩拜單車共享單車進度條實現(xiàn)StepView效果的實例,通過定義五個狀態(tài),分別為:為完成、正在進行、已完成、終點完成、終點未完成。具體實現(xiàn)代碼,大家參考下2017-03-03
Android中使用ContentProvider管理系統(tǒng)資源的實例
這篇文章主要介紹了Android中使用ContentProvider管理系統(tǒng)資源的實例,講解了ContentProvider對系統(tǒng)中聯(lián)系人及多媒體資源的管理例子,需要的朋友可以參考下2016-04-04
Android實現(xiàn)打開各種文件的intent方法小結(jié)
這篇文章主要介紹了Android實現(xiàn)打開各種文件的intent方法,結(jié)合實例形式總結(jié)分析了Android針對HTML、圖片文件、pdf文件、文本文件、音頻文件、視頻文件等的intent打開方法,需要的朋友可以參考下2016-08-08
Android自定義viewgroup可滾動布局 GestureDetector手勢監(jiān)聽(5)
這篇文章主要為大家詳細(xì)介紹了Android自定義viewgroup可滾動布局,GestureDetector手勢監(jiān)聽,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12
Android中判斷網(wǎng)絡(luò)連接是否可用及監(jiān)控網(wǎng)絡(luò)狀態(tài)
獲取網(wǎng)絡(luò)信息需要在AndroidManifest.xml文件中加入相應(yīng)的權(quán)限,接下來詳細(xì)介紹Android中判斷網(wǎng)絡(luò)連接是否可用及監(jiān)控網(wǎng)絡(luò)狀態(tài),感興趣的朋友可以參考下2012-12-12
Android ListView在Fragment中的使用示例詳解
這篇文章主要介紹了Android ListView在Fragment中的使用,因為工作一直在用mvvm框架,因此這篇文章是基于mvvm框架寫的,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-09-09
Android獲取與設(shè)置系統(tǒng)環(huán)境變量的方法指南
這篇文章主要給大家介紹了關(guān)于Android獲取與設(shè)置系統(tǒng)環(huán)境變量的方法指南,文中通過示例代碼介紹的非常詳細(xì),對各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06

