Android自定义控件实现带文字提示的SeekBar

发布时间:2019-08-08 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Android自定义控件实现带文字提示的SeekBar脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

1.写在前面

SeekBar控件在开发中还是比较常见的,比如音视频进度音量调节等,但是原生控件有时还不能满足我们的需求,今天就来学习一下如何自定义SeekBar控件,本文主要实现了一个带文字指示器效果的SeekBar控件

看下最终效果:

Android自定义控件实现带文字提示的SeekBar

IndicatorSeekBar

2.实现

IndicatorSeekBar

 public class IndicatorSeekBar extends AppCompatSeekBar {   // 画笔  PRivate Paint mPaint;  // 进度文字位置信息  private Rect mProgressTextRect = new Rect();  // 滑块按钮度  private int mThumbWidth = dp2px(50);  // 进度指示器宽度  private int mIndicatorWidth = dp2px(50);  // 进度监听  private OnIndicatorSeekBArchangeListener mIndicatorSeekBarChangeListener;   public IndicatorSeekBar(Context context) {  this(context, null);  }   public IndicatorSeekBar(Context context, AttributeSet attrs) {  this(context, attrs, R.attr.seekBarStyle);  }   public IndicatorSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {  suPEr(context, attrs, defStyleAttr);  inIT();  }   private void init() {  mPaint = new TextPaint();  mPaint.setAntiAlias(true);  mPaint.setColor(Color.parseColor("#00574B"));  mPaint.setTextSize(sp2px(16));   // 如果不设置padding,当滑动到最左边或最右边时,滑块会显示不全  setPadding(mThumbWidth / 2, 0, mThumbWidth / 2, 0);   // 设置滑动监听  this.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {  @override  public void onProgressChanged(SeekBar seekBar, int progress, boolean FromUser) {  // NO OP  }   @Override  public void onStartTrackingTouch(SeekBar seekBar) {  if (mIndicatorSeekBarChangeListener != null) {   mIndicatorSeekBarChangeListener.onStartTrackingTouch(seekBar);  }  }   @Override  public void onStopTrackingTouch(SeekBar seekBar) {  if (mIndicatorSeekBarChangeListener != null) {   mIndicatorSeekBarChangeListener.onStopTrackingTouch(seekBar);  }  }  });  }   @Override  protected synchronized void onDraw(Canvas canvas) {  super.onDraw(canvas);  String progressText = getProgress() + "%";  mPaint.getTextBounds(progressText, 0, progressText.length(), mProgressTextRect);   // 进度百分比  float progressRatio = (float) getProgress() / getMax();  // thumb偏移量  float thumbOffset = (mThumbWidth - mProgressTextRect.width()) / 2 - mThumbWidth * progressRatio;  float thumbX = getWidth() * progressRatio + thumbOffset;  float thumbY = getHeight() / 2f + mProgressTextRect.height() / 2f;  canvas.drawText(progressText, thumbX, thumbY, mPaint);   if (mIndicatorSeekBarChangeListener != null) {  float indicatorOffset = getWidth() * progressRatio - (mIndicatorWidth - mThumbWidth) / 2 - mThumbWidth * progressRatio;  mIndicatorSeekBarChangeListener.onProgressChanged(this, getProgress(), indicatorOffset);  }  }   /**  * 设置进度监听  *  * @param listener OnIndicatorSeekBarChangeListener  */  public void setOnSeekBarChangeListener(OnIndicatorSeekBarChangeListener listener) {  this.mIndicatorSeekBarChangeListener = listener;  }   /**  * 进度监听  */  public interface OnIndicatorSeekBarChangeListener {  /**  * 进度监听回调  *  * @param seekBar SeekBar  * @param progress 进度  * @param indicatorOffset 指示器偏移量  */  public void onProgressChanged(SeekBar seekBar, int progress, float indicatorOffset);   /**  * 开始拖动  *  * @param seekBar SeekBar  */  public void onStartTrackingTouch(SeekBar seekBar);   /**  * 停止拖动  *  * @param seekBar SeekBar  */  public void onStopTrackingTouch(SeekBar seekBar);  }   /**  * dp转px  *  * @param dp dp值  * @return px值  */  public int dp2px(float dp) {  return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,  getResources().getDisplayMetrics());  }   /**  * sp转px  *  * @param sp sp值  * @return px值  */  private int sp2px(float sp) {  return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,  getResources().getDisplayMetrics());  } }

重点看下onDraw方法:

 @Override protected synchronized void onDraw(Canvas canvas) {  super.onDraw(canvas);  String progressText = getProgress() + "%";  mPaint.getTextBounds(progressText, 0, progressText.length(), mProgressTextRect);   // 进度百分比  float progressRatio = (float) getProgress() / getMax();  // thumb偏移量  float thumbOffset = (mThumbWidth - mProgressTextRect.width()) / 2 - mThumbWidth * progressRatio;  float thumbX = getWidth() * progressRatio + thumbOffset;  float thumbY = getHeight() / 2f + mProgressTextRect.height() / 2f;  canvas.drawText(progressText, thumbX, thumbY, mPaint);   if (mIndicatorSeekBarChangeListener != null) {  float indicatorOffset = getWidth() * progressRatio - (mIndicatorWidth - mThumbWidth) / 2 - mThumbWidth * progressRatio;  mIndicatorSeekBarChangeListener.onProgressChanged(this, getProgress(), indicatorOffset);  } }

再看一遍效果图:

Android自定义控件实现带文字提示的SeekBar

IndicatorSeekBar

可以看到,进度百分比文字是跟着进度变化在平移的,所以X轴坐标根据进度动态计算就可以了【总宽度 * 进度百分比】(getWidth() * progressRatio),文字需要居中显示,所以需要向右平移【(滑块宽度 - 文字宽度)/ 2】( (mThumbWidth - mProgressTextRect.width()) / 2)。

为了避免滑块滑动到终点时布局被隐藏,需要为SeekBar设置左右padding,距离分别为滑块宽度的一,,所以【控件总长度 = 控件实际长度 + 滑块宽度】,向右平移的过程中就要动态减去滑块宽度【滑块宽度 * 进度百分比】(mThumbWidth * progressRatio),到这里文字的X轴坐标就计算完成了。

文字在平移的过程中始终是垂直居中的,所以Y轴坐标可以这样计算【控件高度 / 2 + 文字高度 / 2】(getHeight() / 2f + mProgressTextRect.height() / 2f),注意drawText方法默认是从左下角开始绘制文字的,如果对绘制文字还不太了解,可以看下这篇文章Android 图解Canvas drawText文字居中的那些事

指示器跟随滑块移动

在IndicatorSeekBar中,向外提供了一个setOnSeekBarChangeListener方法用来回调SeekBar的状态,其中onProgressChanged方法中的indicatorOffset参数就是指示器控件的X坐标,计算方式与上文中进度百分比文字的计算方式一致:

 // 【总宽度 * 进度百分比 -(指示器宽度 - 滑块宽度)/ 2 - 滑块宽度 * 进度百分比】 float indicatorOffset = getWidth() * progressRatio - (mIndicatorWidth - mThumbWidth) / 2 - mThumbWidth * progressRatio; mIndicatorSeekBarChangeListener.onProgressChanged(this, getProgress(), indicatorOffset);

看下如何使用:

 public class MainActivity extends AppCompatActivity {   private TextView tvIndicator;  private IndicatorSeekBar indicatorSeekBar;  private Paint mPaint = new Paint();   @Override  protected void onCreate(Bundle savedInstancestate) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  tvIndicator = findViewById(R.id.tv_indicator);  indicatorSeekBar = findViewById(R.id.indicator_seek_bar);   initData();  }   private void initData() {  final LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) tvIndicator.getLayoutParams();  indicatorSeekBar.setOnSeekBarChangeListener(new IndicatorSeekBar.OnIndicatorSeekBarChangeListener() {   @Override   public void onProgressChanged(SeekBar seekBar, int progress, float indicatorOffset) {   String indicatorText = progress + "%";   tvIndicator.setText(indicatorText);   params.leftMargin = (int) indicatorOffset;   tvIndicator.setLayoutParams(params);   }    @Override   public void onStartTrackingTouch(SeekBar seekBar) {   tvIndicator.setVisibility(View.VISIBLE);   }    @Override   public void onStopTrackingTouch(SeekBar seekBar) {   tvIndicator.setVisibility(View.INVISIBLE);   }  });  } }

布局文件:

 <?XMl version="1.0" encoding="utf-8"?> <RelativeLayout xMLns:andROId="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent">   <LinearLayout  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:layout_centerInParent="true"  android:layout_marginStart="20dp"  android:layout_marginEnd="20dp"  android:orientation="vertical">   <TextView   android:id="@+id/tv_indicator"   android:layout_width="wrap_content"   android:layout_height="wrap_content"   android:background="@drawable/bg_indicator"   android:gravity="center"   android:textColor="#FFFFFF"   android:textSize="16sp"   android:visibility="invisible" />   <com.yl.indicatorseekbar.IndicatorSeekBar   android:id="@+id/indicator_seek_bar"   android:layout_width="match_parent"   android:layout_height="wrap_content"   android:layout_marginTop="5dp"   android:background="@null"   android:max="100"   android:maxHeight="2dp"   android:minHeight="2dp"   android:progress="50"   android:progreSSDrawable="@drawable/seekbar_progress_drawable"   android:thumb="@drawable/seekbar_thumb" />   </LinearLayout>  </RelativeLayout>

3.写在最后

代码已上传至GitHub,欢迎Star、Fork!

GitHub地址:https://github.com/alidili/Demos/tree/master/IndicatorSeekBarDemo

本文Demo的Apk下载地址:

https://github.com/alidili/Demos/raw/master/IndicatorSeekBarDemo/IndicatorSeekBarDemo.apk

总结

android教程
脚本网站
android studio

脚本宝典总结

以上是脚本宝典为你收集整理的Android自定义控件实现带文字提示的SeekBar全部内容,希望文章能够帮你解决Android自定义控件实现带文字提示的SeekBar所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。