android给方法设置进度,Android自定义View实现多节点进度条功能的方法

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

发布时间:2020-07-28 16:05:13

来源:亿速云

阅读:122

作者:小猪

这篇文章主要讲解了Android自定义View实现多节点进度条功能的方法,内容清晰明了,对此有兴趣的小伙伴可以学习一下,相信大家阅读完之后会有帮助。

前言

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

真机效果图

ea0500e6601fae390130e252af11524b.png

04aee661af81c624fd09227c33a03307.png

自定义View完整代码

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

/**

* @description: 节点进度条

* @author: DMingO

* @date: 2020/4/15

*/

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;

/**

* 存储每个圆心在同一直线上的节点圆的 x 坐标值

*/

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);

}

/**

* 测量文字的长宽,将文字视为rect矩形

*/

private void measureText(){

mBounds = new ArrayList<>();

for(String name : textList){

Rect mBound = new Rect();

mTextPaint.getTextBounds(name, 0, name.length(), mBound);

mBounds.add(mBound);

}

}

/**

* 测量view的高度

*/

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);

}

}

}

/**

* 供外部调用,显示控件

* @param titles 底部标题内容列表

* @param indexSet 选中项Set

*/

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();

}

/**

* 更新底部节点标题内容

* @param textList 节点标题内容列表

*/

public void refreshTextList(List textList) {

this.textList = textList;

measureText();

measureHeight();

invalidate();

}

/**

* 获取节点选中状态

* @return 节点选中状态列表

*/

public Set getSelectedIndexSet() {

return selectedIndexSet;

}

/**

* 更新选中项

* @param set 选中项Set

*/

public void refreshSelectedIndexSet(Set set) {

this.selectedIndexSet = set;

invalidate();

}

}

注意点控件的节点总个数是与传入的节点底部标题列表中元素个数控制(相同)的,简而言之就是传入的标题列表中有多少个标题,节点就会绘制多少个

控件通过show方法进行View的初始化和显示内容,传入节点标题列表和节点选中项集合,控制View的选中状态和显示的内容

控件初始化显示后,可以通过refreshTextList(),refreshSelectedIndexSet() 更新标题和选中项

具体不同的颜色,大小可以具体在View中调整

总结

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

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

看完上述内容,是不是对Android自定义View实现多节点进度条功能的方法有进一步的了解,如果还想学习更多内容,欢迎关注亿速云行业资讯频道。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值