今天想使用垂直的seebar,因为系统的是默认水平方向的,所以要想使用垂直方向上的seebar就要自定义了。原理很简单,只需要将水平的seebar,翻转90°就可以了。定义一个类继承于SeekBar,并在OnDraw方法里面旋转一下视图。代码如下:
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) {
//将SeekBar转转90度
c.rotate(-90);
//将旋转后的视图移动回来
c.translate(-getHeight(),0);
Log.i("getHeight()",getHeight()+"");
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:
int i=0;
//获取滑动的距离
i=getMax() - (int) (getMax() * event.getY() / getHeight());
//设置进度
setProgress(i);
Log.i("Progress",getProgress()+"");
//每次拖动SeekBar都会调用
onSizeChanged(getWidth(), getHeight(), 0, 0);
Log.i("getWidth()",getWidth()+"");
Log.i("getHeight()",getHeight()+"");
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
}
另外说说
View在屏幕上显示出来要先经过measure(计算)和layout(布局).
1、什么时候调用onMeasure方法?
当控件的父元素正要放置该控件时调用.父元素会问子控件一个问题,“你想要用多大地方啊?”,然后传入两个参数——widthMeasureSpec和heightMeasureSpec.
这两个参数指明控件可获得的空间以及关于这个空间描述的元数据.
当然,可以直接传递View的高度和宽度到setMeasuredDimension方法里,这样可以直接告诉父控件,需要多大地方放置子控件.
更新内容:
上面的自定义垂直SeekBar我在使用的过程中发现了问题,绑定SeekBar监听之后,想实现拖拽调节屏幕亮度功能,即触摸控件时显示TextView,显示当前屏幕亮度,拖动时实时更新,手指离开屏幕后TextView隐藏,可是不知道为什么,按下以后TextView不显示,拖动时,TextView显示,数据会实时更新,手机离开屏幕后,TextView不消失,即onProgressChanged方法有执行,但是onStartTrackingTouch、onStopTrackingTouch这两个方法莫名奇妙的没有被执行到,查阅很多资料之后,发现了问题的所在,需要在 VerticalSeekBar 类中重写这上面提到的三个方法。下面是重写过的代码:
public class VerticalSeekBar extends SeekBar {
private Drawable mThumb;
private OnSeekBarChangeListener mOnSeekBarChangeListener;
public VerticalSeekBar(Context context) {
super(context,null);
}
public VerticalSeekBar(Context context, AttributeSet attrs) {
super(context, attrs,0);
}
public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(h, w, oldh, oldw);
}
public void setOnSeekBarChangeListener(OnSeekBarChangeListener l) {
mOnSeekBarChangeListener = l;
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(heightMeasureSpec, widthMeasureSpec);
setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}
protected void onDraw(Canvas canvas) {
//将SeekBar转转90度
canvas.rotate(-90);
//将旋转后的视图移动回来
canvas.translate(-getHeight(),0);
super.onDraw(canvas);
}
void onStartTrackingTouch() {
if (mOnSeekBarChangeListener != null) {
mOnSeekBarChangeListener.onStartTrackingTouch(this);
}
}
void onStopTrackingTouch() {
if (mOnSeekBarChangeListener != null) {
onSizeChanged(getWidth(), getHeight(), 0, 0);
mOnSeekBarChangeListener.onStopTrackingTouch(this);
}
}
void onProgressChanged() {
if (mOnSeekBarChangeListener != null) {
mOnSeekBarChangeListener.onProgressChanged(this,getProgress(),true);
}
}
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);
}
}
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, 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);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
onStartTrackingTouch();
setPressed(true);
case MotionEvent.ACTION_MOVE:
onProgressChanged();
//设置进度
int i = getMax() - (int) (getMax() * event.getY() / getHeight());
setProgress(i);
//每次拖动SeekBar都会调用
onSizeChanged(getWidth(), getHeight(), 0, 0);
break;
case MotionEvent.ACTION_UP:
onStopTrackingTouch();
setPressed(false);
break;
case MotionEvent.ACTION_CANCEL:
onStopTrackingTouch();
setPressed(false);
break;
}
return true;
}
public void setThumb(Drawable thumb) {
mThumb = thumb;
super.setThumb(thumb);
}
void attemptClaimDrag() {
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(true);
}
}
}
重写后使用,可以实现原来想要的效果了,但是又出现了一个新的bug,因为在做视频播放器的项目,所以想把在屏幕上下移动调节屏幕的亮度,但是在屏幕上拖动的时候,控件会变成下面这个样子,thumb位置会错乱,但是TextView中实时显示的值是正确的,onProgressChanged方法有被执行到,弄了好久解决不了,重写了onProgressRefresh但是发现并没有什么卵用,因为时间的原因,暂时先决定重改一下布局,不使用垂直的SeekBar,因为使用系统原生的SeekBar调节视频播放进度是没有问题的,所以直接改用原生SeekBar在屏幕顶部显示。这个问题先暂时记着,等忙完再来继续尝试解决,如果有哪位大神,知道怎么解决的,欢迎指导,毕竟我还是Android新手。