2024年安卓最全Android知识笔记:特效系列,仿instagram文字排版特效,2024年最新阿里五面通过率

最后

跳槽季整理面试题已经成了我多年的习惯!在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

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

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

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

String rowStr = text.substring(start,end);
}

但是,但是,但是,这里有一个点需要特别注意,不能通过EditText自带的Layout来计算每行文本,不然拿到的每行文本是错误的。

为什么呢?

举个例子:

如下图所示,当你在第二行将要输入“好”时,因为你输入"好"后该行文本宽度已经大于此时EditText的宽度了,所以“好”字会被认为是重启一行,这样你得到的每行文本就是错的了,因为“好”应该显示在第二行才对。

这就涉及到我在思路探究中提到的第一个问题,无论我字体怎么缩小放大,如何保证每行最多可显示的文本都是一样的?

那么如何保证呢?

其实很简单,因为影响到文字自动换行的因素主要就是字体大小和最大文本宽度,那么只要保证这两个因素不变,无论你输入什么文本,都能准确一致的拆分出每一行的文字。

因为EditText的每行字体在变,而且宽度也在变,所以通过EditText自带的Layout算出的每行文本肯定是错误的。

所以,思路应该是这样的,你需要构建一个用于计算的Layout,这个Layout的字体大小和宽度必须是固定不变的,这样它就能够保证每行最多可容纳的文本始终是一样的,这样我就能够准确拆分出每行文本。

前面已经说过EditText的计算工作都是交给DynamicLayout,所以我们需要创建的是DynamicLayout。代码如下

protected Layout buildCalculateLayout(CharSequence text,TextView host){
TextPaint paint = new TextPaint(host.getPaint());
paint.setTextSize(mDefFontSize);
return new DynamicLayout(text,paint, mDefMaxTextWidth,host.getLayout().getAlignment(),host.getLayout().getSpacingMultiplier(),host.getLayout().getSpacingAdd(),host.getIncludeFontPadding());
}

需要注意的是,这里除了字体大小和宽度,其他的参数都需要跟EditText的参数一样。

其中mDefFontSize是一开始定义的一个默认字体大小,mDefMaxTextWidth是EditText在没动态调整宽度前的宽度(需要减去padding)。

这样子每次都是通过自构建的Layout去计算每行的文本,就不需要考虑EditText的字体和宽度的动态变化。

二.按匹配最大宽度计算每行字体大小

搞定了第一步拆行后,其实已经离成功不远了,接下来就是如何确定每行字体大小了。

确定字体大小说简单简单,说难也难,关键是看你有没有想到那个点。比如一开始我一直纠结于每行文字是怎么随着输入文字个数和行数变化动态改变的,陷入了局部细节,搞得自己晕头转向,如果按照这个方向思考我感觉估计是怎么做都搞不定的。

后来,想了两天后还是没搞明白,我就试着换个思维方式,从整体来考虑,接下来就有种恍然大悟的感觉,原来其实没那么难。

首先,有一个规律是很显然的:

每行文字越多,它的字体就越小,文字越少,字体就越大。

那么我就想一开始时你把每行文字的宽度放大到最大文本宽度,算出匹配这个宽度的字体应该多大,这样文字越少的行,字体就越大,文字越多的行,字体就越小,这个不就是符合那个规律吗。

计算文本宽度的代码如下:

float width = paint.measureText(text);

因为需要通过不断更改字体大小,去算出匹配最大宽度的字体,所以为了减少计算量,一开始可以做一个初始字体大小的换算。

当字体大小是mDefFontSize时对应的文本宽度是mDefMaxTextWidth,那么当文本宽度是x时,对应的字体大小是y,因为字体大小和宽度成反比(宽度越小,字体越大),所以y的计算公式就是:

y = mDefMaxTextWidth \ x * mDefFontSize
x = paint.measureText(text);

这样我们就可以得到一个比较接近目标值的字体大小,这时候再去判断此时文本宽度是否匹配最大文本宽度,不等于的话再去改变字体大小,直到文本宽度匹配最大文本宽度为止。

代码如下:

public float calculateMatchWidthSize(Paint paint,String text,int maxWidth){
float textSize = paint.getTextSize();
float width = paint.measureText(text);

if(maxWidth >= width && maxWidth - width <= text.length()){
return textSize;
}

if(width > maxWidth){
textSize = getNarrowFitTextSize(paint,text,maxWidth,1);
}else{
textSize = getZoomFitTextSize(paint,text,maxWidth,1);
}

return textSize;
}

private float getNarrowFitTextSize(Paint paint,String text,int maxWidth,float rate){
float textSize = paint.getTextSize();
textSize -= 1 * rate;
paint.setTextSize(textSize);
float width = paint.measureText(text);
if(maxWidth >= width && maxWidth - width <= text.length()){
return textSize;
}
//结束条件
if(width < maxWidth){
return getZoomFitTextSize(paint,text,maxWidth,rate);
}else{
return getNarrowFitTextSize(paint,text,maxWidth,rate);
}
}

private float getZoomFitTextSize(Paint paint,String text,int maxWidth,float rate){
float textSize = paint.getTextSize();
textSize += 1 * rate;
paint.setTextSize(textSize);
float width = paint.measureText(text);
if(maxWidth >= width && maxWidth - width <= text.length()){
return textSize;
}
//结束条件
if(width < maxWidth){
return getZoomFitTextSize(paint,text,maxWidth,rate);
}else{
return getNarrowFitTextSize(paint,text,maxWidth,rate);
}
}

三.按匹配最大高度计算每行字体大小

按照匹配最大宽度计算出来的字体会很大,导致文本高度很高,这时候就需要再动态调整每行字体大小,直到文本高度匹配最大高度为止。

动态调整字体大小时,每行文字的字体大小需要按比例调整,比如每行字体都调整为原来的0.9倍大小。

计算每行文本高度的代码:

int height = paint.getFontMetricsInt(null);

为了让每行文本高度的累加值等于文本实际总高度,需要设置EditText的边距为0并且去掉文字上下的空白部分。代码如下:

//去掉文本上下空白区域
mHost.setIncludeFontPadding(false);
//不设置行间距
mHost.setLineSpacing(0,1);

为了提高计算速度,采用二分法来动态调整字体大小,代码如下:

/**

  • 二分法查找合适的字体大小,字体大小按比例调整
  • @return
    */
    private void calculateMatchHeightSizeByRate(float lowRate,float highRate,int minHeight,int maxHeight){
    if(highRate - lowRate <= RATE_SCALE_ERROR_VALUE){
    return;
    }
    float middleRate= (lowRate+highRate)/2;
    scaleFontSizeByRate(middleRate);
    int height = getTextHeight();
    if(height > maxHeight){
    //缩小字体后文字高度大于最大值,需要继续缩小字体
    highRate = middleRate;
    calculateMatchHeightSizeByRate(lowRate,highRate,minHeight,maxHeight);
    } else if(height < minHeight){
    //缩小字体后文字高度小于最小值,需要放大字体
    lowRate = middleRate;
    calculateMatchHeightSizeByRate(lowRate,highRate,minHeight,maxHeight);
    }
    }

private int getTextHeight(){
int totalHeight = 0;
for(CustomSpanData customSpanData: mCustomTextSpanDataList){
int lineHeight = getSingleLineHeight(customSpanData.getTextSize());
totalHeight += lineHeight;
}
return totalHeight;
}

private int getSingleLineHeight(float fontSize){
Paint paint = new Paint(mHost.getPaint());
paint.setTextSize(fontSize);
return paint.getFontMetricsInt(null);
}

private void scaleFontSizeByRate(float rate){
for(int i=0;i<mOriFontSizePxList.size();i++){
float fontSize = mOriFontSizePxList.get(i) * rate;
mCustomTextSpanDataList.get(i).setTextSize(UNIT_PX,fontSize);
}
}

四.重新调整EditText的宽度

前面有提到一个问题那就是输入框的宽度是怎么动态改变的?

阅读了前三个步骤后是不是已经有了答案,首先通过自构建的Layout确定每行需要显示什么文本,然后动态调整每行字体大小以适应输入框的宽高,这时候可能每行的字体已经很小了,如果不调整EditText的宽度必然会导致不同行的文字顶到同一行显示。

所以,最后一步需要把输入框的宽度调整为所有行中宽度最大的那一行的宽度。

最后

为了方便有学习需要的朋友,我把资料都整理成了视频教程(实际上比预期多花了不少精力)

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

  • 无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!
  • 我希望每一个努力生活的IT工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,没有人能随随便便成功。

加油,共勉。

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

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

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

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

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

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值