Git Product home page Git Product logo

aligntextview's Introduction

AlignTextView

字体对齐的TextView

Maven Central

截图

系统要求

Android 4.0以上

快速使用

build.gradle加入dependencies

compile 'me.codeboy.android:align-text-view:2.3.2'

AlignTextView (不支持选择复制,在不需要进行选择复制的情况下使用,排版效果好)

 <me.codeboy.android.aligntextview.AlignTextView
        android:id="@+id/alignTv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

CBAlignTextView (新的版本,支持选择复制,排版效果比较的好)

<me.codeboy.android.aligntextview.CBAlignTextView
        android:id="@+id/cbAlignTv"
        android:textIsSelectable="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

如果需要支持android默认的选择复制,请在xml中加入以下代码:

android:textIsSelectable="true"

相关方法

1.CBAlignTextView

CBAlignTextView中增加了以下方法获取TextView的文本内容,请不要使用getText()获取

getRealText()

由于Android L(5.0)之后对中文的版本进行了变化,造成不能由中文标点作为行首,所以为了能够使CBAlignTextView看起来更加工整,建议将中文符号用英文符号替换(默认不转换),可以通过以下三种方式转化

  • 使用转化函数转化标点符号:

     CBAlignTextViewUtil.replacePunctuation(String text)
    
  • 在设置CBAlignTextView文本前(setText),调用以下方法:

     setPunctuationConvert(boolean convert)
    
  • 如果需要多次设置文本,或者复用组件(如RecyclerView中),在后面每次设置文本前,请调用以下方法:

    reset()
    
  • 可以直接在xml布局中进行设置

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:cb="http://schemas.android.com/apk/res-auto"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical">
       <me.codeboy.android.aligntextview.CBAlignTextView
             android:id="@+id/cbAlignTextView"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             cb:punctuationConvert="true"
             android:textIsSelectable="true"
             android:textSize="14dsp"/>    
     </LinearLayout>
    

2.AlignTextView

AlignTextView是旧的版本,不支持选择复制,但是可以自定义最后一行的对齐方式

setAlign(Align align)

设置每一段最后一行对齐方式,默认居左对齐,同时也可以在xml注释中设置对其方式:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">
  <me.codeboy.android.aligntextview.AlignTextView
        android:id="@+id/alignTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        cb:align="center"
        android:textSize="14dsp"/>    
</LinearLayout>

使用说明

  1. 不用进行选择复制的时候使用 AlignTextView,需要进行选择复制的时候使用CBAlignTextView
  2. AlignTextViewCBAlignTextView在对齐的时候不会对英文单词等进行考虑,它们都是以字符(character)为基础的,不是词(word)。
  3. 使用CBAlignTextView时建议进行中文标点的转换。
  4. demo项目位与app下,可以单独提取出me.codeboy.android.aligntextview.AlignTextView和me.codeboy.android.aligntextview.CBAlignTextView使用。

更新历史

v2.3.2

  1. 修复CBAlignTextView多次设置文本后空行的问题。

v2.3.1

  1. 修复CBAlignTextView在xml中设置text时空指针问题。
  2. 修复CBAlignTextView设置空文本无效问题。

License

Copyright 2016 Yuedong.li

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

有任何问题,欢迎发送邮件到[email protected]交流.

aligntextview's People

Contributors

androiddevelop avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aligntextview's Issues

借用你的思路和框架,修复了空行、偶尔setText无效、padding设置的bug

public class AlignTextView extends AppCompatTextView {

private List<String> lines = new ArrayList<String>(); // 分割后的行
private List<Integer> tailLines = new ArrayList<Integer>(); // 尾行
private Align align = Align.ALIGN_LEFT; // 默认最后一行左对齐

private float lineSpacingMultiplier = 1.0f;
private float lineSpacingAdd = 0.0f;

String oldText;

// 尾行对齐方式
public enum Align {
    ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT  // 居中,居左,居右,针对段落最后一行
}

public AlignTextView(Context context) {
    super(context);
    setTextIsSelectable(false);
}

public AlignTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    setTextIsSelectable(false);

    lineSpacingMultiplier = attrs.getAttributeFloatValue("http://schemas.android" + "" +
            ".com/apk/res/android", "lineSpacingMultiplier", 1.0f);

    int[] attributes = new int[]{android.R.attr.lineSpacingExtra};

    TypedArray arr = context.obtainStyledAttributes(attrs, attributes);

    lineSpacingAdd = arr.getDimensionPixelSize(0, 0);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);   // 计算宽度
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    if (heightMode == MeasureSpec.EXACTLY) {
        // 确定高度,直接返回
        setMeasuredDimension(getMeasuredWidth(), heightSize);
    } else {
        recalc();

        int height = lines.size() * getLineHeight();

        if (heightMode ==  MeasureSpec.AT_MOST) {
            // 最小高度
            setMeasuredDimension(getMeasuredWidth(), Math.min(heightSize, height));
        } else {
            setMeasuredDimension(getMeasuredWidth(), height);
        }
    }
}

@Override
protected void onDraw(Canvas canvas) {
    TextPaint paint = getPaint();
    paint.setColor(getCurrentTextColor());
    paint.drawableState = getDrawableState();

    Paint.FontMetrics fm = paint.getFontMetrics();
    float firstHeight = getTextSize() - (fm.bottom - fm.descent + fm.ascent - fm.top);

    int gravity = getGravity();
    if ((gravity & 0x1000) == 0) { // 是否垂直居中
        firstHeight = firstHeight + (getTextSize() - firstHeight) / 2;
    }

    int paddingTop = getPaddingTop();
    int paddingLeft = getPaddingLeft();
    int paddingRight = getPaddingRight();
    int width = getMeasuredWidth() - paddingLeft - paddingRight;

    for (int i = 0; i < lines.size(); i++) {
        float drawY = i * getLineHeight() + firstHeight;
        String line = lines.get(i);
        // 绘画起始x坐标
        float drawSpacingX = paddingLeft;
        float gap = (width - paint.measureText(line));
        float interval = gap / (line.length() - 1);

        // 绘制最后一行
        if (tailLines.contains(i)) {
            interval = 0;
            if (align == Align.ALIGN_CENTER) {
                drawSpacingX += gap / 2;
            } else if (align == Align.ALIGN_RIGHT) {
                drawSpacingX += gap;
            }
        }

        for (int j = 0; j < line.length(); j++) {
            float drawX = paint.measureText(line.substring(0, j)) + interval * j;
            canvas.drawText(line.substring(j, j + 1), drawX + drawSpacingX, drawY + paddingTop, paint);
        }
    }
}

/**
 * 设置尾行对齐方式
 *
 * @param align 对齐方式
 */
public void setAlign(Align align) {
    this.align = align;
    invalidate();
}

private void recalc() {
    String text = getText().toString();
    if (text.equals(oldText))
        return;
    oldText = text;

    TextPaint paint = getPaint();
    lines.clear();
    tailLines.clear();

    // 文本含有换行符时,分割单独处理
    String[] items = text.split("\\n");
    for (String item : items) {
        calc(paint, item);
    }
}

/**
 * 计算每行应显示的文本数
 *
 * @param text 要计算的文本
 */
private void calc(Paint paint, String text) {
    if (text.length() == 0) {
        lines.add("\n");
        return;
    }
    int width = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
    int startPosition = 0; // 起始位置
    StringBuilder sb = new StringBuilder();
    for(int i = 0; i < text.length(); ++i) {
        if(paint.measureText(text.substring(startPosition, i + 1)) > (float) width) {
            startPosition = i;
            this.lines.add(sb.toString());
            sb = new StringBuilder();
            i--;
        } else {
            sb.append(text.charAt(i));
        }
    }

    if(sb.length() > 0) {
        lines.add(sb.toString());
    }

    tailLines.add(Integer.valueOf(this.lines.size() - 1));
}

}

请教一行代码的意思

int ignoreCalcLength = (int) (width / oneChineseWidth); // 忽略计算的长度

  1. 忽略计算 是什么意思?
  2. 为什么只考虑中文字符的宽度

width设置wrap_content就无效.

CBAlignTextView如果设置 android:layout_width="wrap_content" 而不是match_parent的话,CBAlignTextView的宽度会是0。希望可以重写onmeasure解决这个问题.

会超出屏幕显示的范围

有时候字符串会超出屏幕显示的范围,比如红色字体部分,最后一个字符就超出了范围。
试着修改了一下,不过是在上一个版本上进行的修改,不知道正确与否。具体修改点如下:
①Line180 int ignoreCalcLength = (int) (width / oneChineseWidth + 0.99);
→ int ignoreCalcLength = (int) (width / oneChineseWidth );
②Line200 i = i + ignoreCalcLength;
→ i = i + ignoreCalcLength-1;

image

有个bug

有个bug,每次都会一闪一下,计算高度。体验不太好

ListView中item使用AlignTextView,5.0版本系统机器出现内容乱序现象

你好,大神,开发中测试包了个TextView文本框显示文字右边没对齐的bug,感谢您的开源组件,使我快速解决这个问题。

但是在测试过程中,发现Android系统版本4.1.2的三星机器,没出现问题,而Android系统版本5.0.2的三星机器出现乱序现象,具体表现为前面三项原先是A、B、C,列表下滑再回到顶部,前面三项变为B、A、C。初步怀疑是不是新版本系统优化TextView导致的。

在下qq 1830560854,欢迎一起解决问题,:)。

AlignTextView复制

AlignTextView 排版较好,怎么解决不能复制问题呢,CBAlignTextView排版不是太好,AlignTextView不能复制的原因是什么?

lineSpacingExtra 问题

很棒的一种排版方法 只是我在使用过程中发现 lineSpacingExtra 设置越大 文字最后一行有可能会导致显示不全...

CBAlignTextView在Listview或者Recyclerview中有时候settext无效bug

CBAlignTextView在我的项目里Listview中,如果手指一直拖动listview滑动,屏幕显示外的第一条数据就不会显示,如果是随意滑动的话就会显示.(比如listview一个屏幕只能显示5条数据,那么我拖动listview往上滑,那么第6条数据滑进屏幕的时候CBAlignTextView是不显示text的,但是如果我是快速滑动一下就松开,那么第6条数据是可以显示的。)后面我特地从githup下了你的example运行下,发现你的example里也有无效的情况。

screenshot_2018-01-04-14-13-08-250_me codeboy android aligntextview example

Can not support ImageSpan (不支持ImageSpan)

发现个问题,使用TextView显示多个ImageSpan内容时,TextView本身没有左右对齐的话,在TextView最后追加ImageSpan的时候会有问题。
本来想使用你这个库,但发现并不支持ImageSpan。。。
是否后续有支持的打算

TextView展示带图片的Html

Html.fromHtml()里面的ImageGetter取回图片在AlignTextView上无法显示,在TextView上是没问题的。我看了您重写的onLayout和onDraw,又看了TextView源码里的onLayout onDraw,还是不得要领。不知道您能否帮助我解答,不胜感谢。

底部空白问题 & 显示不全

我在5.1.1的机器上还有6.0.1机型上跑 表现近乎完美,但是我用Gennymotion模拟器跑 低分辨率的设备上发现(480 * 800 还有960 * 540 )底部空白问题还是偶尔存在,系统版本号是4.1.1 . 我是用在recyclerview中的。而这个多余的空白表现的很明显,会错乱。同时也有时候会出现文字没有显示全就被截断了. 感觉是Line size 计算有问题

没有支持emoji表情

我看了下代码貌似对系统原生的表情支持,现在输入表情会出现乱码

控件的 visibility 属性不能设置为gone

在将控件的visiblity属性设置为gone 之后,程序会崩溃。错误原因如下:
java.lang.StringIndexOutOfBoundsException: length=189; regionStart=0; regionLength=-1

at java.lang.AbstractStringBuilder.startEndAndLength(AbstractStringBuilder.java:211)
at java.lang.AbstractStringBuilder.substring(AbstractStringBuilder.java:616)
at java.lang.StringBuilder.substring(StringBuilder.java:44)
at me.codeboy.android.aligntextview.CBAlignTextView.processLine(CBAlignTextView.java:174)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.