栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 移动开发 > Android

Android 自定义View实现多节点进度条功能

Android 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android 自定义View实现多节点进度条功能

前言

最近项目有一个节点进度条的小需求,完成后,想分享出来希望可以帮到有需要的同学。

真机效果图

自定义View完整代码

开箱即用~,注释已经炒鸡详细了


public class PointProcessBar extends View {
  
  private Paint mLinePaint;
  
  private Paint mLineSelectedPaint;
  
  private Paint mTextPaint;
  
  private Paint mTextSelPaint;
  
  private Paint mCirclePaint;
  
  private Paint mCircleSelPaint;
  
  private Paint mCircleStrokeSelPaint;
  
  private int mColorUnselected = Color.parseColor("#1ca8b0d9");
  
  private int mColorSelected = Color.parseColor("#61A4E4");
  
  private int mColorTextUnselected = Color.parseColor("#5c030f09");
  
  int circleCount ;
  
  float mLineHeight = 7f;
  //圆的直径
  float mCircleHeight = 50f;
  float mCircleSelStroke = 8f;
  float mCircleFillRadius = 15f;
  //文字大小
  float mTextSize = 35f;
  //文字离顶部的距离
  float mMarginTop = 40f;
  
  float marginLeft = 30f;
  
  float marginRight = marginLeft;
  
  float divideWidth;
  int defaultHeight;
  
  List textList = new ArrayList<>();
  
  List mBounds;
  
  List circleLineJunctions = new ArrayList<>();
  
  Set selectedIndexSet = new HashSet<>();
  public PointProcessBar(Context context) {
    super(context);
  }
  public PointProcessBar(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    initPaint();
  }
  public PointProcessBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
  }
  public PointProcessBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
  }
  
  private void initPaint(){
    mLinePaint = new Paint();
    mLineSelectedPaint = new Paint();
    mCirclePaint = new Paint();
    mTextPaint = new Paint();
    mCircleStrokeSelPaint = new Paint();
    mTextSelPaint=new Paint();
    mCircleSelPaint = new Paint();
    mLinePaint.setColor(mColorDef);
    //设置填充
    mLinePaint.setStyle(Paint.Style.FILL);
    //笔宽像素
    mLinePaint.setStrokeWidth(mLineHeight);
    //锯齿不显示
    mLinePaint.setAntiAlias(true);
    mLineSelectedPaint.setColor(mColorSelected);
    mLineSelectedPaint.setStyle(Paint.Style.FILL);
    mLineSelectedPaint.setStrokeWidth(mLineHeight);
    mLineSelectedPaint.setAntiAlias(true);
    mCirclePaint.setColor(mColorDef);
    //设置填充
    mCirclePaint.setStyle(Paint.Style.FILL);
    //笔宽像素
    mCirclePaint.setStrokeWidth(1);
    //锯齿不显示
    mCirclePaint.setAntiAlias(true);
    //选中时外框空心圆圈画笔
    mCircleStrokeSelPaint.setColor(mColorSelected);
    mCircleStrokeSelPaint.setStyle(Paint.Style.STROKE);
    mCircleStrokeSelPaint.setStrokeWidth(mCircleSelStroke);
    mCircleStrokeSelPaint.setAntiAlias(true);
    //选中时的内部填充圆画笔
    mCircleSelPaint.setStyle(Paint.Style.FILL);
    mCircleSelPaint.setStrokeWidth(1);
    mCircleSelPaint.setAntiAlias(true);
    mCircleSelPaint.setColor(mColorSelected);
    //普通状态的文本 画笔
    mTextPaint.setTextSize(mTextSize);
    mTextPaint.setColor(mColorTextDef);
    mTextPaint.setAntiAlias(true);
    mTextPaint.setTextAlign(Paint.Align.CENTER);
    //选中后的文本画笔
    mTextSelPaint.setTextSize(mTextSize);
    mTextSelPaint.setColor(mColorSelected);
    mTextSelPaint.setAntiAlias(true);
    mTextSelPaint.setTextAlign(Paint.Align.CENTER);
  }
  
  private void measureText(){
    mBounds = new ArrayList<>();
    for(String name : textList){
      Rect mBound = new Rect();
      mTextPaint.getTextBounds(name, 0, name.length(), mBound);
      mBounds.add(mBound);
    }
  }

  
  private void measureHeight(){
    if (mBounds!=null && mBounds.size()!=0) {
      defaultHeight = (int) (mCircleHeight + mMarginTop + mCircleSelStroke + mBounds.get(0).height()/2);
    } else {
      defaultHeight = (int) (mCircleHeight + mMarginTop+mCircleSelStroke);
    }
  }
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
    //宽高都设置为wrap_content
    if(widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST){
      //宽设置为wrap_content
      setMeasuredDimension(widthSpecSize,defaultHeight);
    }else if(widthSpecMode == MeasureSpec.AT_MOST){
      setMeasuredDimension(widthSpecSize,heightSpecSize);
    }else if(heightSpecMode == MeasureSpec.AT_MOST){
      //高设置为wrap_content
      setMeasuredDimension(widthSpecSize, defaultHeight);
    }else{
      //宽高都设置为match_parent或具体的dp值
      setMeasuredDimension(widthSpecSize, heightSpecSize);
    }
  }
  @Override
  protected void onDraw(Canvas canvas) {
    //若未设置节点标题或者选中项的列表,则取消绘制
    if (textList == null || textList.isEmpty() ||
 selectedIndexSet == null || selectedIndexSet.isEmpty() ||
 mBounds == null || mBounds.isEmpty()) {
      return;
    }
    //画灰色圆圈的个数
    circleCount=textList.size();
    //每个圆相隔的距离(重要),可以通过这个调节节点间距
    divideWidth = (getWidth() - mCircleHeight ) / (circleCount - 1);
    //绘制文字和圆形
    for (int i=0; i < circleCount ;i++){
      float cx;
      float cy;
      float textX;
      if (i==0){
 //第一个节点,圆心需要向右偏移
 cx = mCircleHeight / 2 + i * divideWidth + marginLeft;
 cy = mCircleHeight / 2 + mCircleSelStroke;
 textX = cx;
 circleLineJunctions.add(cx + mCircleHeight / 2);
      }else if (i==textList.size()-1){
 //最后一个节点,圆心需要向左偏移
 cx = mCircleHeight / 2 + i * divideWidth - marginRight;
 cy = mCircleHeight / 2 + mCircleSelStroke;
 textX = cx;
 circleLineJunctions.add(cx - mCircleHeight / 2);
      }else {
 //中间部分的节点
 cx = mCircleHeight / 2 + i * divideWidth;
 cy = mCircleHeight / 2+mCircleSelStroke;
 textX = cx;
 circleLineJunctions.add(cx - mCircleHeight / 2);
 circleLineJunctions.add(cx + mCircleHeight / 2);
      }
      if (getSelectedIndexSet().contains(i)){
 //若当前位置节点被包含在选中项Set中,判定此节点被选中
 canvas.drawCircle(cx , cy, mCircleHeight / 2, mCircleStrokeSelPaint);
 canvas.drawCircle(cx, cy, mCircleFillRadius, mCircleSelPaint);
 canvas.drawText(textList.get(i), textX, (float) (mCircleHeight + mMarginTop +mCircleSelStroke+mBounds.get(i).height()/2.0), mTextSelPaint);
      }else {
 //若当前位置节点没有被包含在选中项Set中,判定此节点没有被选中
 canvas.drawCircle(cx , cy, mCircleHeight / 2, mCirclePaint);
 canvas.drawText(textList.get(i), textX, (float) (mCircleHeight + mMarginTop +mCircleSelStroke+mBounds.get(i).height()/2.0), mTextPaint);
      }
    }
    for(int i = 1 , j = 1 ; j <= circleLineJunctions.size() && ! circleLineJunctions.isEmpty() ; ++i , j=j+2){
      if(getSelectedIndexSet().contains(i)){
 canvas.drawLine(circleLineJunctions.get(j-1),mCircleHeight/2+mCircleSelStroke,
     circleLineJunctions.get(j) ,mCircleHeight/2+mCircleSelStroke,mLineSelectedPaint);
      }else {
 canvas.drawLine(circleLineJunctions.get(j-1),mCircleHeight/2+mCircleSelStroke,
     circleLineJunctions.get(j) ,mCircleHeight/2+mCircleSelStroke,mLinePaint);
      }
    }
  }
  
  public void show(List titles , Set indexSet){
    if(titles != null && ! titles.isEmpty()){
      this.textList = titles;
    }
    if(indexSet != null && ! indexSet.isEmpty()){
      this.selectedIndexSet = indexSet;
    }
    measureText();
    measureHeight();
    //绘制
    invalidate();
  }
  
  public void refreshTextList(List textList) {
    this.textList = textList;
    measureText();
    measureHeight();
    invalidate();
  }
  
  public Set getSelectedIndexSet() {
    return selectedIndexSet;
  }
  
  public void refreshSelectedIndexSet(Set set) {
    this.selectedIndexSet = set;
    invalidate();
  }
}

注意点

  • 控件的节点总个数是与传入的节点底部标题列表中元素个数控制(相同)的,简而言之就是传入的标题列表中有多少个标题,节点就会绘制多少个
  • 控件通过show方法进行View的初始化和显示内容,传入节点标题列表和节点选中项集合,控制View的选中状态和显示的内容
  • 控件初始化显示后,可以通过refreshTextList(),refreshSelectedIndexSet() 更新标题和选中项
  • 具体不同的颜色,大小可以具体在View中调整

总结

可以看到效果不复杂,因此自定义View的代码行数不多,也很容易看懂,直接拿走代码即可在项目中食用啦。

由于不同项目设计稿会有不同,这里也仅仅给有需要的同学一个思路,可以改造具体实现代码~

到此这篇关于Android 自定义View实现多节点进度条功能的文章就介绍到这了,更多相关android 自定义view 进度条内容请搜索考高分网以前的文章或继续浏览下面的相关文章希望大家以后多多支持考高分网!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/154133.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号