Android自定义控件:一款多特效的智能loadingView,Android高级

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

height = measuredHeight(heightMeasureSpec); //这里是测量控件大小

width = measureWidth(widthMeasureSpec); //我们经常可以看到我们设置控件wrap_content,match_content或者固定值

setMeasuredDimension(width, height);

}

下面以measureWidth为例:

private int measureWidth(int widthMeasureSpec) {

int result;

int specMode = MeasureSpec.getMode(widthMeasureSpec);

int specSize = MeasureSpec.getSize(widthMeasureSpec);

//这里是精准模式,比如match_content,或者是你控件里写明了控件大小

if (specMode == MeasureSpec.EXACTLY) {

result = specSize;

} else {

//这里是wrap_content模式,其实这里就是给一个默认值

//下面这段注销代码是最开始如果用户不设置大小,给他一个默认固定值。这里以字体长度来决定更合理

//result = (int) getContext().getResources().getDimension(R.dimen.dp_150);

//这里是我设置的长度,当然你写自定义控件可以设置你想要的逻辑,根据你的实际情况

result = buttonString.length() * textSize + height * 5 / 3;

if (specMode == MeasureSpec.AT_MOST) {

result = Math.min(result, specSize);

}

}

return result;

}

3、【绘制文字text】

这里我是用自己的方式实现:当文字长度超过控件长度时,文字需要来回滚动。所以自定义控件因为你需要什么样的功能可以自己去实现(当然这个方法也是在onDraw里,为什么这么个顺序讲,目的希望我希望你能循序渐进的理解,如果你觉得onDraw方代码太杂,你可以用个方法独立出去,你可以跟作者一样用private void drawText(Canvas canvas) {}),

//绘制文字的路径(文字过长时,文字来回滚动需要用到)

private Path textPath = new Path():

textRect.left = 0;

textRect.top = 0;

textRect.right = width;

textRect.bottom = height; //这里确定文字绘制区域,其实就是控件区域

Paint.FontMetricsInt fontMetrics = textPaint.getFontMetricsInt();

//这里是获取文字绘制的y轴位置,可以理解上下居中

int baseline = (textRect.bottom + textRect.top - fontMetrics.bottom - fontMetrics.top) / 2;

//这里判断文字长度是否大于控件长度,当然我控件2边需要留文字的间距,所以不是大于width,这么说只是更好的理解

//这里是当文字内容大于控件长度,启动回滚效果。建议先看下面else里的正常情况

if ((buttonString.length() * textSize) > (width - height * 5 / 3)) {

textPath.reset();

//因为要留2遍间距,以heigh/3为间距

textPath.moveTo(height / 3, baseline);

textPath.lineTo(width - height / 3, baseline);

//这里的意思是文字从哪里开始写,可以是居中,这里是右边

textPaint.setTextAlign(Paint.Align.RIGHT);

//这里是以路径绘制文字,scrollSize可以理解为文字在x轴上的便宜量,同时,我的混动效果就是通过改变scrollSize

//刷新绘制来实现

canvas.drawTextOnPath(buttonString, textPath, scrollSize, 0, textPaint);

if (isShowLongText) {

//这里是绘制遮挡物,因为绘制路径没有间距这方法,所以绘制遮挡物类似于间距方式

canvas.drawRect(new Rect(width - height / 2 - textSize / 3, 0, width - height / 2, height),paintOval);

canvas.drawRect(new Rect(height / 2, 0, height / 2 + textSize / 3, height), paintOval);

//这里有个bug 有个小点-5 因画笔粗细产生

canvas.drawArc(new RectF(width - height, 0, width - 5, height), -90, 180, true, paintOval);

canvas.drawArc(new RectF(0, 0, height, height), 90, 180, true, paintOval);

}

if (animator_text_scroll == null) {

//这里是计算混到最右边和最左边的距离范围

animator_text_scroll = ValueAnimator.ofInt(buttonString.length() * textSize - width + height * 2 / 3,-textSize);

//这里是动画的时间,scrollSpeed可以理解为每个文字滚动控件外所需的时间,可以做成控件属性提供出去

animator_text_scroll.setDuration(buttonString.length() * scrollSpeed);

//设置动画的模式,这里是来回滚动

animator_text_scroll.setRepeatMode(ValueAnimator.REVERSE);

//设置插值器,让整个动画流畅

animator_text_scroll.setInterpolator(new LinearInterpolator());

//这里是滚动次数,-1无限滚动

animator_text_scroll.setRepeatCount(-1);

animator_text_scroll.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

//改变文字路径x轴的偏移量

scrollSize = (int) animation.getAnimatedValue();

postInvalidate();

}

});

animator_text_scroll.start();

}

} else {

//这里是正常情况,isShowLongText,是我在启动控件动画的时候,是否启动 文字有渐变效果的标识,

//如果是长文字,启动渐变效果的话,如果控件变小,文字内容在当前控件外,会显得很难看,所以根据这个标识,关闭,这里你可以先忽略(同时因为根据路径绘制text不能有间距效果,这个标识还是判断是否在控件2遍绘制遮挡物,这是作者的解决方式,如果你有更好的方式可以在下方留言)

isShowLongText = false;

/**

  • 简单的绘制文字,没有考虑文字长度超过控件长度

  • */

//这里是居中显示

textPaint.setTextAlign(Paint.Align.CENTER);

//参数1:文字

//参数2,3:绘制文字的中心点

//参数4:画笔

canvas.drawText(buttonString, textRect.centerX(), baseline, textPaint);

}

4、【自定义控件属性】
<?xml version="1.0" encoding="utf-8"?>

这里以,文案为例, textStr。比如你再布局种用到app:txtStr=“文案内容”。在自定义控件里获取如下:

public SmartLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

//自定义控件的3参方法的attrs就是我们设置自定义属性的关键

//比如我们再attrs.xml里自定义了我们的属性,

TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.SmartLoadingView);

//这里是获取用户有没有设置整个属性

//这里是从用户那里获取有没有设置文案

String title = typedArray.getString(R.styleable.SmartLoadingView_textStr);

if (TextUtils.isEmpty(title)){

//如果获取来的属性是空,那么可以默认一个属性

//(作者忘记设置了!因为已经发布后期优化,老尴尬了)

buttonString =“默认文案”;

}else{

//如果有设置文案

buttonString = title;

}

}

5、【设置点击事件,启动动画】

为了点击事件的直观,也可以把处理防止重复点击事件封装在里面

//这是我自定义登录点击的接口

public interface LoginClickListener {

void click();

}

public void setLoginClickListener(final LoginClickListener loginClickListener) {

this.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

if (loginClickListener != null) {

//防止重复点击

if (!isAnimRuning) {

start();

loginClickListener.click();

}

}

}

});

}

6、【动画讲解】
6.1、第一个动画,矩形到正方形,以及矩形到圆角矩形(这里是2个动画,只是同时进行)

矩形到正方形(为了简化,我把源码一些其他属性去掉了,这样方便理解)

//其中 default_all_distance = (w - h) / 2;除以2是因为2遍都往中间缩短

private void set_rect_to_circle_animation() {

//这是一个属性动画,current_left 会在duration时间内,从0到default_all_distance匀速变化

//想添加多样化的话 还可以加入插值器。

animator_rect_to_square = ValueAnimator.ofInt(0, default_all_distance);

animator_rect_to_square.setDuration(duration);

animator_rect_to_square.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

//这里的current_left跟onDraw相关,还记得吗

//onDraw里的控件区域

//控件左边区域 rectf.left = current_left;

//控件右边区域 rectf.right = width - current_left;

current_left = (int) animation.getAnimatedValue();

//刷新绘制

invalidate();

}

});

矩形到圆角矩形。就是从一个没有圆角的变成完全圆角的矩形,当然我展示的时候只有第三个图,最后一个按钮才明显了。

其他的我直接设置成了圆角按钮,因为我把圆角做成了一个属性。

还记得onDraw里的canvas.drawRoundRect(rectf, circleAngle, circleAngle, paint);circleAngle就是圆角的半径

可以想象一下如果全是圆角,那么circleAngle会是多少,当然是height/2;没错吧,所以

因为我把圆角做成了属性obtainCircleAngle是从xml文件获取的属性,如果不设置,则为0,就没有任何圆角效果

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-BoQGWBO8-1710921355452)]
[外链图片转存中…(img-CT8bN7mG-1710921355453)]
[外链图片转存中…(img-WPnClfeO-1710921355454)]
[外链图片转存中…(img-effbeWp7-1710921355454)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-alw9ax7Y-1710921355455)]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值