• Android-使用StaticLayout实现icon跟随TextView末尾效果


    Android-使用StaticLayout实现icon跟随TextView末尾效果

    👉关于作者

    已经工作三年的95后程序员,坐标上海。平时在公司写Android原生App,业余时间会抽空学习Java后端,目标是成为全栈工程师,志同道合的可以私我聊聊haha。加入CSDN快4年了,看了很多优秀作者的博客收获很多。后面的时间里,我也会整理一些工作中使用到的知识分享出来。我的座右铭:人生在勤,不索何获。大家一起努力加油吧

    👉正文部分

    1、StaticLayout基本使用

    通过drawText方法绘制出的文字超过一行后不会自动换行,StaticLayout可以对文字进行换行;TextView也用了StaticLayout

    1、使用

    @Override
    protected void onDraw(Canvas canvas) {
      TextPaint tp = new TextPaint();
      //Paint设置字体大小的单位时像素,要将dp转为px设置
      tp.setTextSize(UiUtils.dip2px(mContext,20));
      tp.setColor(Color.parseColor("#111111"));
      tp.setFakeBoldText(true);
      tp.setAntiAlias(true);
      tp.setStyle(Paint.Style.FILL);
      String text = "在Android开发中,Canvas.drawText不会换行,即使一个很长的字符串也只会显示一行,超出部分会隐藏在屏幕之外.StaticLayout是android中处理文字的一个工具类,StaticLayout 处理了文字换行的问题";
      //执行该方法后绘制出的文本不会进行换行
      //        canvas.drawText(text,0,UiUtils.dip2px(mContext,200),tp);
      StaticLayout staticLayout = new StaticLayout(text, tp, canvas.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false);
      staticLayout.draw(canvas);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2、构造器

    public StaticLayout(CharSequence source, TextPaint paint, int outerwidth,Alignment align,float spacingmult, float spacingadd,boolean includepad){
    }
    
    • 1
    • 2
    • source:文本
    • paint:画笔
    • outerWidth:一行的宽度
    • align:文本对齐方式
    • spacingmult:行间距
    • spacingadd:在行间距的基础上增加的值
    • includepad:略,设置false

    2、使用StaticLayout实现icon跟随TextView末尾效果

    在RelativeLayout中有一个TextView和ImageView,TextView会动态改变其内容,ImageView要始终跟着TextView的末尾处

    1、效果图

    在这里插入图片描述

    2、XML代码

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp">
    
        <TextView
            android:id="@+id/tv"
            style="@style/style_title_light_black_size_14"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/follow_textview_demo"/>
    
        <ImageView
            android:id="@+id/iv"
            android:layout_width="16dp"
            android:layout_height="16dp"
            android:src="@drawable/question_gray_icon"/>
    
    RelativeLayout>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3、实现思路

    1、如何获取TextView每一行文本的最右边位置

    当TextView换行了,我们得知道TextView最底部的那一行的文本写到什么位置,这样ImageView可以跟着这个位置去显示。答案是用StaticLayout去获取,代码如下

    //先要按照TextView的Style生成一个Paint
    TextPaint tp = new TextPaint();
    tp.setStyle(Paint.Style.FILL);
    tp.setTextSize(UiUtils.dip2px(FollowTextViewDemoActivity.this,14));
    tp.setColor(Color.parseColor("#111111"));
    tp.setAntiAlias(true);
    
    StaticLayout sl = new StaticLayout(tv.getText(), tp, tv.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false);
    int lineBottom = sl.getLineBottom(sl.getLineCount() - 1);
    float lineRight = sl.getLineRight(sl.getLineCount() - 1);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    2、ImageView跟在TextView末尾会跑出屏幕外

    ImageView跟在TextView末尾有两种情况:ImageView跟在TextView后面可以显示出来;ImageView跟在TextView后面不会显示出来。第一种,也就是TextView的文本没有占满屏幕宽度,ImageView可以在文本的末尾显示出来;第二种,TextView的文本几乎占满屏幕宽度,ImageView在文本后面显示,就跑出屏幕外了。第二种情况我们就要对TextView进行重新setText,将目前的文本以最后一个字符为分割线,中间加入换行符,这样原本会占满屏幕的TextView会重新换一行,此时ImageView再跟在后面就不会跑出屏幕了

    StaticLayout sl;
    TextPaint tp = new TextPaint();
    tp.setStyle(Paint.Style.FILL);
    tp.setTextSize(UiUtils.dip2px(FollowTextViewDemoActivity.this,14));
    tp.setColor(Color.parseColor("#111111"));
    tp.setAntiAlias(true);
    
    tv.post(new Runnable() {
      @Override
      public void run() {
        sl = new StaticLayout(tv.getText(), tp, tv.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false);
        float lineRight = sl.getLineRight(sl.getLineCount() - 1);
        //如果TextView最后一行文本的最右边+ImageView的marginLeft+ImageView的大小超出了屏幕宽度
        if ((int)lineRight + UiUtils.dip2px(FollowTextViewDemoActivity.this,6)+ UiUtils.dip2px(FollowTextViewDemoActivity.this,16) > tv.getWidth()){
          //将现有文本的最后一个字符前加入换行符,以使TextView最后一行再换一行出来,就解决上面ImageView超出屏幕宽度的问题
          String text = tv.getText().toString();
          String substring1 = text.substring(0, text.length() - 1);
          String substring2 = text.substring(text.length() - 1);
          text = String.format("%s\n%s",substring1,substring2);
          tv.setText(text);
          tv.post(new Runnable() {
            @Override
            public void run() {
              //ImageView位置:底部和TextView底部同一位置,左边=TextView的最后一行文本的右边+ImageView的marginLeft
              sl = new StaticLayout(tv.getText(), tp, tv.getWidth(), Layout.Alignment.ALIGN_NORMAL, 1f, 0f, false);
              float lineRight = sl.getLineRight(sl.getLineCount() - 1);
              RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) iv.getLayoutParams();
              lp.topMargin = tv.getHeight() - lp.height;
              lp.leftMargin = (int)lineRight + UiUtils.dip2px(FollowTextViewDemoActivity.this,6);
              Log.e("FollowTextViewDemo","topMargin:"+lp.topMargin+",leftMargin:"+lp.leftMargin);
              iv.setLayoutParams(lp);
            }
          });
        }else {
          //ImageView位置:底部和TextView底部同一位置,左边=TextView的最后一行文本的右边+ImageView的marginLeft
          RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) iv.getLayoutParams();
          lp.topMargin = tv.getHeight() - lp.height;
          lp.leftMargin = (int)lineRight + UiUtils.dip2px(FollowTextViewDemoActivity.this,6);
          Log.e("FollowTextViewDemo","topMargin:"+lp.topMargin+",leftMargin:"+lp.leftMargin);
          iv.setLayoutParams(lp);
        }
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    参考文章

    StaticLayout的使用详解

    android TextView文字换行内容末尾跟图标或其他View的实现

  • 相关阅读:
    HTTP 跨域名请求(CORS)
    宝塔node建立软连接,解决command not found问题
    python 服务器数据转发数据 跳板机?
    蓝牙耳机哪种通话效果最好?通话质量最好的蓝牙耳机盘点
    UI案例——登陆系统
    公司会倒闭,但大模型肯定不会
    性能测试01
    【大数据入门核心技术-Hive】Hive3.1.2高可用集群搭建
    10月 kaggle-酶稳定性预测(群链接)
    [附源码]java毕业设计小锅米线点餐管理系统
  • 原文地址:https://blog.csdn.net/qq_42948831/article/details/126137451