开发自定义View对于初中级开发者都是一个比较头痛的问题,工作中遇到一个需求,需要做一个自定义的SeekBar,效果图如下所示,看到这个需求的时候,我觉得可以使用组合控件的方式来封装一个自定义的SeekBar,那么让我们开始吧!
public class SeekBarView extends RelativeLayout {
/**
* 左边图片
*/
private ImageView mIvLeft;
/**
* 右边图片
*/
private ImageView mIvRight;
/**
* 原生的seekBar对象
*/
private SeekBar mSeekBar;
/**
* 滑块
*/
private Drawable mThumbDrawable;
/**
* 当前进度
*/
private int mProgress;
/**
* 左边text
*/
private TextView mTvLeft;
/**
* 右边text
*/
private TextView mTvRight;
/**
* 左右都是image
*/
public static final int IMAGE_IMAGE = 1;
/**
* 左边image,右边text
*/
public static final int IMAGE_TEXT = 2;
/**
* 左右两边都是text
*/
public static final int TEXT_TEXT = 3;
/**
* 加减操作模式
*/
public static final int OPERATE_IMAGE = 4;
/**
* 首尾皆可滑动
*/
public static final int RANGE_SEEKBAR = 5;
/**
* 当前设置的seekBar模式
*/
private int mCurrentMode;
/**
* 设置的seekBar最大值
*/
private int mMaxValue = -1;
/**
* 加减点击的监听
*/
private onAddRemoveProgressListener mListener;
/**
* seekBar滑动监听
*/
private onSeekBarChangeListener mOnSeekBarChangeListener;
private RangeSeekBar mRangeSeekBar;
private Context mContext;
public SeekBarView(Context context) {
super(context);
}
public SeekBarView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
init();
}
public SeekBarView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void init() {
LayoutInflater.from(mContext).inflate(R.layout.seek_bar_view, this);
mIvLeft = findViewById(R.id.iv_left);
mIvRight = findViewById(R.id.iv_right);
mTvLeft = findViewById(R.id.tv_left);
mTvRight = findViewById(R.id.tv_right);
mSeekBar = findViewById(R.id.seek_bar);
mThumbDrawable = getResources().getDrawable(R.drawable.thumb_click);
//设置滑块
mSeekBar.setThumb(mThumbDrawable);
mRangeSeekBar = findViewById(R.id.range_seek_bar);
//给原生的seekBar设置滑动监听
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(mOnSeekBarChangeListener!=null){
mOnSeekBarChangeListener.onProgress(progress);
}
mProgress = progress;
mTvRight.setText(String.valueOf(progress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
/**
* 设置seekBar的模式
*
* @param mode
*/
public void setMode(int mode) {
mCurrentMode = mode;
if (mode == IMAGE_IMAGE) {
mIvLeft.setVisibility(VISIBLE);
mIvRight.setVisibility(VISIBLE);
}
if (mode == IMAGE_TEXT) {
mIvLeft.setVisibility(VISIBLE);
mTvRight.setVisibility(VISIBLE);
mTvRight.setText(String.valueOf(mProgress));
}
if (mode == TEXT_TEXT) {
mTvLeft.setVisibility(VISIBLE);
mTvRight.setVisibility(VISIBLE);
}
if (mode == OPERATE_IMAGE) {
mIvLeft.setImageResource(R.drawable.ic_remove_48px);
mIvRight.setImageResource(R.drawable.ic_add_48px);
mIvLeft.setVisibility(VISIBLE);
mIvRight.setVisibility(VISIBLE);
initListener();
}
if (mode == RANGE_SEEKBAR) {
mSeekBar.setVisibility(GONE);
mRangeSeekBar.setVisibility(VISIBLE);
mTvLeft.setVisibility(VISIBLE);
mTvRight.setVisibility(VISIBLE);
/**
* 双向滑动seekBar设置监听
*/
mRangeSeekBar.setOnRangeChangedListener(new OnRangeChangedListener() {
@Override
public void onRangeChanged(RangeSeekBar view, float min, float max, boolean isFromUser) {
int mi = (int) min;
int mx = (int) max;
mTvLeft.setText(String.valueOf(mi));
mTvRight.setText(String.valueOf(mx));
}
@Override
public void onStartTrackingTouch(RangeSeekBar view, boolean isLeft) {
}
@Override
public void onStopTrackingTouch(RangeSeekBar view, boolean isLeft) {
}
});
}
}
/**
* 初始化加减按钮监听
*/
private void initListener() {
mIvLeft.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mProgress > 0) {
mProgress--;
}
mSeekBar.setProgress(mProgress);
mListener.onProgressBack(mProgress);
}
});
mIvRight.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mMaxValue != -1) {
if (mProgress < mMaxValue) {
mProgress++;
}
}
mSeekBar.setProgress(mProgress);
mListener.onProgressBack(mProgress);
}
});
}
/**
* 设置seekBar是否可滑动和加减操作是否有效
*
* @param b 是否禁用 false:禁用 true:开启
*/
public void setSeekBarStatus(int mode, boolean b) {
if (mode == RANGE_SEEKBAR) {
if (b) {
mRangeSeekBar.setEnabled(true);
mRangeSeekBar.getLeftSeekBar().setThumbDrawableId(R.drawable.thumb_click);
mRangeSeekBar.getRightSeekBar().setThumbDrawableId(R.drawable.thumb_click);
mRangeSeekBar.setProgressColor(ContextCompat.getColor(mContext, R.color.c201));
} else {
mRangeSeekBar.setEnabled(false);
mRangeSeekBar.getLeftSeekBar().setThumbDrawableId(R.drawable.thumb_unclick);
mRangeSeekBar.getRightSeekBar().setThumbDrawableId(R.drawable.thumb_unclick);
mRangeSeekBar.setProgressColor(ContextCompat.getColor(mContext, R.color.c125));
}
} else {
if (b) {
mSeekBar.setEnabled(true);
/**
* 设置滑动块
*/
mThumbDrawable = getResources().getDrawable(R.drawable.thumb_click);
mSeekBar.setThumb(mThumbDrawable);
/**
* 设置seekBar背景和滑过部分的颜色
*/
Drawable drawable = getResources().getDrawable(R.drawable.seekbar_clickable_colors);
/**
* 为了解决设置背景时,seekBar宽度变化的问题
*/
Rect bounds = mSeekBar.getProgressDrawable().getBounds();
mSeekBar.setProgressDrawable(drawable);
mSeekBar.getProgressDrawable().setBounds(bounds);
/**
* seekBar设置背景颜色及滑过部分颜色
*/
mSeekBar.setProgressDrawable(drawable);
mIvLeft.setClickable(true);
mIvRight.setClickable(true);
} else {
mSeekBar.setEnabled(false);
mThumbDrawable = getResources().getDrawable(R.drawable.thumb_unclick);
mSeekBar.setThumb(mThumbDrawable);
Drawable drawable = getResources().getDrawable(R.drawable.seekbar_unclickable_colors);
Rect bounds = mSeekBar.getProgressDrawable().getBounds();
mSeekBar.setProgressDrawable(drawable);
mSeekBar.getProgressDrawable().setBounds(bounds);
mIvLeft.setClickable(false);
mIvRight.setClickable(false);
}
}
}
/**
* 除RANGE_SEEKBAR模式下,用于设置seekBar的最大值
*
* @param value
*/
public void setMax(int value) {
if(mCurrentMode != RANGE_SEEKBAR){
mMaxValue = value;
mSeekBar.setMax(value);
}
}
/**
* 除RANGE_SEEKBAR、IMAGE_IMAGE、OPERATE_IMAGE模式下,用于设置seekBar当前值
*
* @param value
*/
public void setCurrentProgress(int value) {
mSeekBar.setProgress(value);
if (mCurrentMode != RANGE_SEEKBAR&&mCurrentMode!=IMAGE_IMAGE&&mCurrentMode!=OPERATE_IMAGE) {
mTvRight.setText(String.valueOf(value));
mSeekBar.setProgress(value);
}
}
/**
* 除RANGE_SEEKBAR模式,用于获取当前进度
* @return
*/
public int getCurrentProgress(){
return mProgress;
}
/**
* 设置左边图片资源
*
* @param r
*/
public void setLeftImage(int r) {
if (mCurrentMode != RANGE_SEEKBAR&&mCurrentMode!=TEXT_TEXT) {
mIvLeft.setVisibility(VISIBLE);
mIvLeft.setImageResource(r);
}
}
/**
* 设置右边图片资源
*
* @param r
*/
public void setRightImage(int r) {
if (mCurrentMode != RANGE_SEEKBAR&&mCurrentMode!=TEXT_TEXT) {
mIvRight.setVisibility(VISIBLE);
mIvRight.setImageResource(r);
}
}
/**
* 设置左边文字
*
* @param t
*/
public void setLeftText(String t) {
if(mCurrentMode==TEXT_TEXT) {
mTvLeft.setText(t);
}
}
/**
* 加减模式下使用,初始化加减点击监听
*
* @param listener
*/
public void setOnAddRemoveProgressListener(onAddRemoveProgressListener listener) {
mListener = listener;
}
/**
* 加减模式下使用,加减点击监听
*/
public interface onAddRemoveProgressListener {
void onProgressBack(int progress);
}
public interface onSeekBarChangeListener{
void onProgress(int progress);
}
/**
* seekBar滑动监听
* @param listener
*/
public void setOnSeekBarChangeListener(onSeekBarChangeListener listener){
mOnSeekBarChangeListener = listener;
}
/**
* 仅限RANGE_SEEKBAR模式下使用,用于设置seekbar的最小最大范围
*
* @param min
* @param max
*/
public void setRangeValue(int min, int max) {
mRangeSeekBar.setRangeRules(min, max, 5, 1);
mTvLeft.setText(String.valueOf(min));
mTvRight.setText(String.valueOf(max));
}
/**
* 获取左边text的值
*
* @return
*/
public String getLeftTextValue() {
return mTvLeft.getText().toString();
}
/**
* 获取右边text的值
*
* @return
*/
public String getRightTextValue() {
return mTvRight.getText().toString();
}
/**
* 当RANGE_SEEKBAR模式下需要设置背景时,调用此方法,seekbar整个的背景颜色需要在Activity中设置,在配合此方法方可达到效果
*/
public void setRangeModelBackgroundSettings(){
mTvLeft.setTextColor(ContextCompat.getColor(mContext,R.color.c126));
mTvRight.setTextColor(ContextCompat.getColor(mContext,R.color.c126));
mRangeSeekBar.setProgressDefaultColor(ContextCompat.getColor(getContext(), R.color.c125));
}
}
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<solid android:color="#e0e0e0"/>
shape>
item>
<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
<solid android:color="#11ce33"/>
shape>
clip>
item>
<item android:id="@android:id/progress">
<clip>
<shape>
<solid android:color="#ffa516" />
shape>
clip>
item>
layer-list>