广告
返回顶部
首页 > 资讯 > 精选 >Android中怎么仿instagram实现文字自动排版功能
  • 261
分享到

Android中怎么仿instagram实现文字自动排版功能

2023-06-04 22:06:08 261人浏览 独家记忆
摘要

这篇文章主要介绍“Android中怎么仿instagram实现文字自动排版功能”,在日常操作中,相信很多人在Android中怎么仿instagram实现文字自动排版功能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家

这篇文章主要介绍“Android中怎么仿instagram实现文字自动排版功能”,在日常操作中,相信很多人在Android中怎么仿instagram实现文字自动排版功能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Android中怎么仿instagram实现文字自动排版功能”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

1 概述

玩过ins的朋友应该知道ins里面有一个编辑文字自动排版的功能,应用会根据用户输入的每行文字自动进行排版,以达到一个紧凑美观的效果。

效果图如下:

Android中怎么仿instagram实现文字自动排版功能

2 思路探究

因为网上找不到什么相关的资料,所以就直接通过玩ins猜测大概的实现思路,我整理下自己一开始的一些疑问。

当输入的文字越来越多,字体越来越小时怎么保证每行最多能够显示的文本不变?

正常情况下,当你字体越来越小而输入框宽度不变时,那么你每行可输入的文字就会变多,但是你发现ins无论字体多大,每行最多能容纳的文本是不变。我猜测可能是输入框会随着字体的变化而改变。

通过打开开发者选项的应用布局边界,可以看到确实ins的输入框的宽度是动态变化的。

下面是打开应用布局边界后的效果图:

Android中怎么仿instagram实现文字自动排版功能

当然,这里可能会引入一个新的问题,那就是输入框的宽度是怎么动态改变的?

好让它刚好能够在字体大小变化的过程中最多可容纳的文本数不变。

这个问题会在下面说,这里先不展开。

每行字体大小是怎么确定的,又是怎样联动变化的?

这个问题一开始想了很久,我觉得如果把这个问题搞明白基本就已经成功一半了。大部分人一开始可能都会很容易陷入局部思维,包括我也一样,一直在纠结每行字体是怎么变化的,但其实应该要从整体考虑,从整体考虑一切都会变得很简单,代码实现上也会变得更加容易,不需要处理各种特殊情况。

具体思路:

遍历每行文本,以适应最大文本宽度算出每行的字体大小,然后以每行的字体大小算出每行行高度,把每行行高度累加得到文本总高度,然后判断文本总高度是否大于最大文本高度,如果大于则按比例缩小每行的字体大小,以缩小每行的行高度,得到新的文本总高度,直到文本总高度小于最大文本高度。

上面的这么大段文字总结起来其实就4个步骤:

  1. 拆行

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

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

  4. 重新调整EditText宽度

3 知识储备

在动手之前我们需要知道几个相关知识点:

span

span可以使TextView分段显示不同样式的文字。在自动排版中因为每行文字字体大小不一样,所以我们需要为每行文字设置不同的span。

Layout

Layout是一个用于各种文本计算的辅助类,TextView的文字排版布局都是依赖于Layout实现的。因为Layout是完全跟TextView解耦的,所以我们可以构建合适的Layout来帮助我们计算字体大小。

下面是Layout的官方定义:

A base class that manages text layout in visual elements on the screen.

For text that will be edited, use a DynamicLayout, which will be updated as the text changes. For text that will not change, use a StaticLayout.

Layout有几个子类,其中较常用的是DynamicLayout和StaticLayout,按照官方的说法,当你的文本是可编辑的则使用的是DynamicLayout,当你的文本不可编辑那么就使用StaticLayout。

所以说EditText的文本计算工作应该都是交给了DynamicLayout实现。

4 具体实现

首先我们需要监听文字的输入变化,当文本变化时去计算每行的字体大小,最终渲染到屏幕。监听文本变化的代码如下:

  addTextChangedListener(new TextWatcher() {            @Override            public void beforeTextChanged(CharSequence s, int start, int count, int after) {            }            @Override            public void onTextChanged(CharSequence s, int start, int before, int count) {                refresh();            }            @Override            public void afterTextChanged(Editable s) {            }        });

一.拆行

监听到文本变化后需要对文本进行拆行,得到每行的文字。我们可以通过Layout实现,代码如下:

String text = layout.getText().toString();int lineCount = layout.getLineCount();        for (int i = 0; i < lineCount; i++) {            int start = layout.getLineStart(i);            int end = layout.getLineEnd(i);            String rowStr = text.substring(start,end);        }

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

为什么呢?

举个例子:

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

Android中怎么仿instagram实现文字自动排版功能

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

那么如何保证呢?

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

因为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 * mDefFontSizex = 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);

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

        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的宽度必然会导致不同行的文字顶到同一行显示。

到此,关于“Android中怎么仿instagram实现文字自动排版功能”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: Android中怎么仿instagram实现文字自动排版功能

本文链接: https://www.lsjlt.com/news/240120.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Android中怎么仿instagram实现文字自动排版功能
    这篇文章主要介绍“Android中怎么仿instagram实现文字自动排版功能”,在日常操作中,相信很多人在Android中怎么仿instagram实现文字自动排版功能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家...
    99+
    2023-06-04
  • Android怎么实现自动文本框提示功能
    这篇文章主要介绍Android怎么实现自动文本框提示功能,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!具体内容如下activity_main.xml布局<LinearLayout xmlns:andr...
    99+
    2023-05-30
    android
  • Android中怎么实现文本内容自动朗读功能
    Android中怎么实现文本内容自动朗读功能,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Android提供了自动朗读支持。自动朗读支持可以对指定文本内容进行朗读,从而发生声音...
    99+
    2023-05-30
    android
  • Android中怎么实现动画自动播放功能
    本篇文章给大家分享的是有关Android中怎么实现动画自动播放功能,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。具体如下:private ImageView ...
    99+
    2023-05-31
    android
  • android怎么实现自动点击功能
    要实现Android自动点击功能,可以使用Android提供的AccessibilityService服务。步骤如下:1. 创建一个...
    99+
    2023-10-07
    android
  • android自动截图功能怎么实现
    要在Android中实现自动截图功能,可以使用以下步骤:1. 在AndroidManifest.xml文件中添加权限声明,以允许访问...
    99+
    2023-08-24
    android
  • css怎么实现文字过长自动隐藏功能
    这篇文章给大家分享的是有关css怎么实现文字过长自动隐藏功能的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。单行overflow: hidden;text-overflow: ellipsis;...
    99+
    2023-06-08
  • android中怎么实现长按选择文字功能
    android中怎么实现长按选择文字功能,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1.实现原理原理其实也不难,简单总结就是:绘制文字时把显示的文字的坐标记录下来(记录文...
    99+
    2023-05-31
    android
  • 怎么在Android中实现一个自动打卡功能
    这篇文章给大家介绍怎么在Android中实现一个自动打卡功能,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。提前准备首先我们需要一直不用的Android手机,插上公司的电源。下载安装钉钉并设置为极速打卡。自动打开我们只需...
    99+
    2023-06-14
  • Android中怎么实现一个图片文字识别功能
    Android中怎么实现一个图片文字识别功能,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。添加依赖implementation 'com.rmtheis:...
    99+
    2023-06-20
  • Android中怎么实现文件下载功能
    今天就跟大家聊聊有关Android中怎么实现文件下载功能,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。普通单线程下载文件:直接使用URLConnection.openStream()...
    99+
    2023-05-31
    android
  • Android中怎么实现仿iOS侧滑退出当前界面功能
    小编给大家分享一下Android中怎么实现仿iOS侧滑退出当前界面功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!首先看下效果图:分析:(1)要想模仿ios的这...
    99+
    2023-05-30
  • HTML5中怎么实现文字轮滚功能
    这篇文章将为大家详细讲解有关HTML5中怎么实现文字轮滚功能,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。marquee标签是实现文字轮滚的大功臣常用属性如...
    99+
    2022-10-19
  • 怎么在Android中利用orc实现一个文字识别功能
    这篇文章给大家介绍怎么在Android中利用orc实现一个文字识别功能,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、什么是orcorc是指利用光学字符识别(ORC全称:Optical Character Recog...
    99+
    2023-05-31
    android orc roi
  • spring boot怎么实现自动输出word文档功能
    这篇文章主要介绍了spring boot怎么实现自动输出word文档功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。springboot是什么springboot一种全新的...
    99+
    2023-06-14
  • js怎么实现文字选中分享功能
    小编给大家分享一下js怎么实现文字选中分享功能,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!总结:文字选中IE和其他浏览器不一样...
    99+
    2022-10-19
  • Vue中怎么实现动态表格的排序功能
    这篇文章主要介绍“Vue中怎么实现动态表格的排序功能”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Vue中怎么实现动态表格的排序功能”文章能帮助大家解决问题。首先,为了实现动态表格的排序,我们需要一...
    99+
    2023-07-06
  • 怎么在微信小程序中实现一个文字滚动功能
    怎么在微信小程序中实现一个文字滚动功能?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。具体内容如下wxml:<view>显示完后再显示:</vi...
    99+
    2023-06-14
  • Android中怎么利用Xfermode实现动态文字加载动画
    这篇文章将为大家详细讲解有关Android中怎么利用Xfermode实现动态文字加载动画,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。第一步:我们要熟悉一下这个图16个图形结果,其实现在有1...
    99+
    2023-05-30
    android
  • Python/MySQL怎么实现Excel文件自动处理数据功能
    今天小编给大家分享一下Python/MySQL怎么实现Excel文件自动处理数据功能的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一...
    99+
    2023-07-05
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作