2024年最新Android 打造形形色色的进度条 实现可以如此简单,安卓音视频面试题

总结

写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个关于Flutter的学习思路及方向,从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。
由于内容较多就只放上一个大概的大纲,需要更及详细的学习思维导图的
还有高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术资料,并且还有技术大牛一起讨论交流解决问题。

跨平台开发:Flutter.png

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

没错,这就是我们的进度条效果,横向的模仿了daimajia的进度条样子。不过我们继承子ProgressBar,简单的为其整个容,代码清晰易懂 。为什么说,易懂呢?

横向那个进度条,大家会drawLine()和drawText()吧,那么通过getWidth()拿到控件的宽度,再通过getProgress()拿到进度,按比例控制绘制线的长短,字的位置还不是分分钟的事。

github源码地址Android-ProgressBarWidthNumber欢迎大家star or fork 。

3、实现

====

横向的滚动条绘制肯定需要一些属性,比如已/未到达进度的颜色、宽度,文本的颜色、大小等。

本来呢,我是想通过系统ProgressBar的progressDrawable,从里面提取一些属性完成绘制需要的参数的。但是,最终呢,反而让代码变得复杂。所以最终还是改用自定义属性。 说道自定义属性,大家应该已经不陌生了。

1、HorizontalProgressBarWithNumber


1、自定义属性

values/attr_progress_bar.xml:

<?xml version="1.0" encoding="utf-8"?>

2、构造中获取

public class HorizontalProgressBarWithNumber extends ProgressBar

{

private static final int DEFAULT_TEXT_SIZE = 10;

private static final int DEFAULT_TEXT_COLOR = 0XFFFC00D1;

private static final int DEFAULT_COLOR_UNREACHED_COLOR = 0xFFd3d6da;

private static final int DEFAULT_HEIGHT_REACHED_PROGRESS_BAR = 2;

private static final int DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR = 2;

private static final int DEFAULT_SIZE_TEXT_OFFSET = 10;

/**

  • painter of all drawing things

*/

protected Paint mPaint = new Paint();

/**

  • color of progress number

*/

protected int mTextColor = DEFAULT_TEXT_COLOR;

/**

  • size of text (sp)

*/

protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE);

/**

  • offset of draw progress

*/

protected int mTextOffset = dp2px(DEFAULT_SIZE_TEXT_OFFSET);

/**

  • height of reached progress bar

*/

protected int mReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_REACHED_PROGRESS_BAR);

/**

  • color of reached bar

*/

protected int mReachedBarColor = DEFAULT_TEXT_COLOR;

/**

  • color of unreached bar

*/

protected int mUnReachedBarColor = DEFAULT_COLOR_UNREACHED_COLOR;

/**

  • height of unreached progress bar

*/

protected int mUnReachedProgressBarHeight = dp2px(DEFAULT_HEIGHT_UNREACHED_PROGRESS_BAR);

/**

  • view width except padding

*/

protected int mRealWidth;

protected boolean mIfDrawText = true;

protected static final int VISIBLE = 0;

public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs)

{

this(context, attrs, 0);

}

public HorizontalProgressBarWithNumber(Context context, AttributeSet attrs,

int defStyle)

{

super(context, attrs, defStyle);

setHorizontalScrollBarEnabled(true);

obtainStyledAttributes(attrs);

mPaint.setTextSize(mTextSize);

mPaint.setColor(mTextColor);

}

/**

  • get the styled attributes

  • @param attrs

*/

private void obtainStyledAttributes(AttributeSet attrs)

{

// init values from custom attributes

final TypedArray attributes = getContext().obtainStyledAttributes(

attrs, R.styleable.HorizontalProgressBarWithNumber);

mTextColor = attributes

.getColor(

R.styleable.HorizontalProgressBarWithNumber_progress_text_color,

DEFAULT_TEXT_COLOR);

mTextSize = (int) attributes.getDimension(

R.styleable.HorizontalProgressBarWithNumber_progress_text_size,

mTextSize);

mReachedBarColor = attributes

.getColor(

R.styleable.HorizontalProgressBarWithNumber_progress_reached_color,

mTextColor);

mUnReachedBarColor = attributes

.getColor(

R.styleable.HorizontalProgressBarWithNumber_progress_unreached_color,

DEFAULT_COLOR_UNREACHED_COLOR);

mReachedProgressBarHeight = (int) attributes

.getDimension(

R.styleable.HorizontalProgressBarWithNumber_progress_reached_bar_height,

mReachedProgressBarHeight);

mUnReachedProgressBarHeight = (int) attributes

.getDimension(

R.styleable.HorizontalProgressBarWithNumber_progress_unreached_bar_height,

mUnReachedProgressBarHeight);

mTextOffset = (int) attributes

.getDimension(

R.styleable.HorizontalProgressBarWithNumber_progress_text_offset,

mTextOffset);

int textVisible = attributes

.getInt(R.styleable.HorizontalProgressBarWithNumber_progress_text_visibility,

VISIBLE);

if (textVisible != VISIBLE)

{

mIfDrawText = false;

}

attributes.recycle();

}

嗯,看起来代码挺长,其实都是在获取自定义属性,没什么技术含量。

3、onMeasure

刚才不是出onDraw里面写写就行了么,为什么要改onMeasure呢,主要是因为我们所有的属性比如进度条宽度让用户自定义了,所以我们的测量也得稍微变下。

@Override

protected synchronized void onMeasure(int widthMeasureSpec,

int heightMeasureSpec)

{

int heightMode = MeasureSpec.getMode(heightMeasureSpec);

if (heightMode != MeasureSpec.EXACTLY)

{

float textHeight = (mPaint.descent() + mPaint.ascent());

int exceptHeight = (int) (getPaddingTop() + getPaddingBottom() + Math

.max(Math.max(mReachedProgressBarHeight,

mUnReachedProgressBarHeight), Math.abs(textHeight)));

heightMeasureSpec = MeasureSpec.makeMeasureSpec(exceptHeight,

MeasureSpec.EXACTLY);

}

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

宽度我们不变,所以的自定义属性不涉及宽度,高度呢,只考虑不是EXACTLY的情况(用户明确指定了,我们就不管了),根据padding和进度条宽度算出自己想要的,如果非EXACTLY下,我们进行exceptHeight封装,传入给控件进行测量高度。

测量完,就到我们的onDraw了~~~

4、onDraw

@Override

protected synchronized void onDraw(Canvas canvas)

{

canvas.save();

//画笔平移到指定paddingLeft, getHeight() / 2位置,注意以后坐标都为以此为0,0

canvas.translate(getPaddingLeft(), getHeight() / 2);

boolean noNeedBg = false;

//当前进度和总值的比例

float radio = getProgress() * 1.0f / getMax();

//已到达的宽度

float progressPosX = (int) (mRealWidth * radio);

//绘制的文本

String text = getProgress() + “%”;

//拿到字体的宽度和高度

float textWidth = mPaint.measureText(text);

float textHeight = (mPaint.descent() + mPaint.ascent()) / 2;

//如果到达最后,则未到达的进度条不需要绘制

if (progressPosX + textWidth > mRealWidth)

{

progressPosX = mRealWidth - textWidth;

noNeedBg = true;

}

// 绘制已到达的进度

float endX = progressPosX - mTextOffset / 2;

if (endX > 0)

{

mPaint.setColor(mReachedBarColor);

mPaint.setStrokeWidth(mReachedProgressBarHeight);

canvas.drawLine(0, 0, endX, 0, mPaint);

}

// 绘制文本

if (mIfDrawText)

{

mPaint.setColor(mTextColor);

canvas.drawText(text, progressPosX, -textHeight, mPaint);

}

// 绘制未到达的进度条

if (!noNeedBg)

{

float start = progressPosX + mTextOffset / 2 + textWidth;

mPaint.setColor(mUnReachedBarColor);

mPaint.setStrokeWidth(mUnReachedProgressBarHeight);

canvas.drawLine(start, 0, mRealWidth, 0, mPaint);

}

canvas.restore();

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh)

{

super.onSizeChanged(w, h, oldw, oldh);

mRealWidth = w - getPaddingRight() - getPaddingLeft();

}

其实核心方法就是onDraw了,但是呢,onDraw也很简单,绘制线、绘制文本、绘制线,结束。

还有两个简单的辅助方法:

/**

  • dp 2 px

  • @param dpVal

*/

protected int dp2px(int dpVal)

{

return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,

dpVal, getResources().getDisplayMetrics());

}

/**

  • sp 2 px

  • @param spVal

  • @return

*/

protected int sp2px(int spVal)

{

return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,

spVal, getResources().getDisplayMetrics());

}

好了,到此我们的横向进度就结束了,是不是很简单~~如果你是自定义View,你还得考虑progress的更新,考虑状态的销毁与恢复等等复杂的东西。

接下来看我们的RoundProgressBarWidthNumber圆形的进度条。

2、RoundProgressBarWidthNumber


圆形的进度条和横向的进度条基本变量都是一致的,于是我就让RoundProgressBarWidthNumber extends HorizontalProgressBarWithNumber 了。

然后需要改变的就是测量和onDraw了:

完整代码:

package com.zhy.view;

import android.content.Context;

import android.content.res.TypedArray;

import android.graphics.Canvas;

import android.graphics.Paint.Cap;

import android.graphics.Paint.Style;

import android.graphics.RectF;

import android.util.AttributeSet;

import com.zhy.library.view.R;

public class RoundProgressBarWidthNumber extends

HorizontalProgressBarWithNumber {

/**

  • mRadius of view

*/

private int mRadius = dp2px(30);

public RoundProgressBarWidthNumber(Context context) {

this(context, null);

建议

当我们出去找工作,或者准备找工作的时候,我们一定要想,我面试的目标是什么,我自己的技术栈有哪些,近期能掌握的有哪些,我的哪些短板 ,列出来,有计划的去完成,别看前两天掘金一些大佬在驳来驳去 ,他们的观点是他们的,不要因为他们的观点,膨胀了自己,影响自己的学习节奏。基础很大程度决定你自己技术层次的厚度,你再熟练框架也好,也会比你便宜的,性价比高的替代,很现实的问题但也要有危机意识,当我们年级大了,有哪些亮点,与比我们经历更旺盛的年轻小工程师,竞争。

  • 无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!!!!!!!!

  • 准备想说怎么样写简历,想象算了,我觉得,技术就是你最好的简历

  • 我希望每一个努力生活的it工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。

  • 有什么问题想交流,欢迎给我私信,欢迎评论

【附】相关架构及资料

Android高级技术大纲

面试资料整理

内含往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

己技术层次的厚度,你再熟练框架也好,也会比你便宜的,性价比高的替代,很现实的问题但也要有危机意识,当我们年级大了,有哪些亮点,与比我们经历更旺盛的年轻小工程师,竞争。

  • 无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!!!!!!!!

  • 准备想说怎么样写简历,想象算了,我觉得,技术就是你最好的简历

  • 我希望每一个努力生活的it工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。

  • 有什么问题想交流,欢迎给我私信,欢迎评论

【附】相关架构及资料

[外链图片转存中…(img-VmVrLUTd-1715135465390)]

[外链图片转存中…(img-5ieH8Mjs-1715135465390)]

内含往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值