TextView 相关

TextView展开与折叠的动画

001.png
001.gif
  • 怎么用?

<pre>
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private TextView tvContent;
private TextView tvEx;
private TextLineHelper textLayoutHelper;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    findViewById(R.id.tv_ex).setOnClickListener(this);
    tvContent = (TextView) findViewById(R.id.tv_content);
    tvEx = (TextView) findViewById(R.id.tv_ex);
    textLayoutHelper = new TextLineHelper.Builder()
            .textView(tvContent)
            .minLines(2)
            .maxLines(10)
            .min2MaxDuration(500)
            .max2MinDuration(500)
            .build().onLineFinishListener(new MyOnLineFinishListener());
}

@Override
public void onClick(View view) {
    if (R.id.tv_ex == view.getId()) {
        textLayoutHelper.toggleTextLayout();
    }
}

private final class MyOnLineFinishListener implements TextLineHelper.OnLineFinishListener {

    /\*\*
     \* @param textView
     \* @param isMin2Max 是 由最小行数 到 最大行数
     \*/
    @Override
    public void onLineFinish(TextView textView, boolean isMin2Max) {
        if (isMin2Max) {
            tvEx.setText("收回");
        } else {
            tvEx.setText("展开");
        }
    }
}

}

</pre>

  • 核心代码

<pre>
package github.alex.textlayout;

import android.animation.ObjectAnimator;
import android.util.Property;
import android.widget.TextView;

/**
* 作者:Alex
* 时间:2016年08月24日 20:52
* 博客:http://www.jianshu.com/users/c3c4ea133871/subscriptions
*/

public class TextLineHelper {
private boolean isMaxLines;
private int lines;
private ObjectAnimator max2MinLinesObjectAnimator;
private ObjectAnimator min2MaxLinesObjectAnimator;
private Builder builder;
private OnLineFinishListener onLineFinishListener;

private TextLineHelper(Builder builder) {
    this.builder = builder;
    isMaxLines = false;
    max2MinLinesObjectAnimator = ObjectAnimator.ofInt(this, new LineProperty(Integer.class, "max2Min"), builder.maxLines, builder.minLines);
    min2MaxLinesObjectAnimator = ObjectAnimator.ofInt(this, new LineProperty(Integer.class, "min2Max"), builder.minLines, builder.maxLines);
    max2MinLinesObjectAnimator.setDuration(builder.max2MinDuration);
    min2MaxLinesObjectAnimator.setDuration(builder.min2MaxDuration);
}

public void toggleTextLayout() {
    if (isMaxLines) {
        max2MinLinesObjectAnimator.start();
    } else {
        min2MaxLinesObjectAnimator.start();
    }
    isMaxLines = !isMaxLines;
}

private final class LineProperty extends Property<TextLineHelper, Integer> {
    private String name;

    public LineProperty(Class<Integer> type, String name) {
        super(type, name);
        this.name = name;
    }

    @Override
    public Integer get(TextLineHelper object) {
        return object.getLines();
    }

    @Override
    public void set(TextLineHelper object, Integer value) {
        object.setLines(value);
        //LogUtil.e("value = " + value + " minLines = " + builder.minLines + " maxLines = " + builder.maxLines + " isMaxLines = " + isMaxLines + " name = " + name);
        if ((onLineFinishListener != null) && (value == builder.maxLines) && isMaxLines && "min2Max".equals(name)) {
            onLineFinishListener.onLineFinish(builder.textView, true);
        } else if ((onLineFinishListener != null) && (value == builder.minLines) && (!isMaxLines) && ("max2Min".equals(name))) {
            onLineFinishListener.onLineFinish(builder.textView, false);
        }
    }
}

private void setLines(int lines) {
    builder.textView.setMaxLines(lines);
    this.lines = lines;
}

private int getLines() {
    return lines;
}

public TextLineHelper onLineFinishListener(OnLineFinishListener onLineFinishListener) {
    this.onLineFinishListener = onLineFinishListener;
    return this;
}

public interface OnLineFinishListener {
    /\*\*
     \* @param textView
     \* @param isMin2Max 是 由最小行数 到 最大行数
     \*/
    void onLineFinish(TextView textView, boolean isMin2Max);
}

public static class Builder {
    private long min2MaxDuration;
    private long max2MinDuration;
    private int minLines;
    private int maxLines;
    private TextView textView;

    public Builder textView(TextView textView) {
        this.textView = textView;
        return this;
    }

    public Builder min2MaxDuration(long min2MaxDuration) {
        this.min2MaxDuration = min2MaxDuration;
        return this;
    }

    public Builder max2MinDuration(long max2MinDuration) {
        this.max2MinDuration = max2MinDuration;
        return this;
    }

    public Builder minLines(int minLines) {
        this.minLines = minLines;
        return this;
    }

    public Builder maxLines(int maxLines) {
        this.maxLines = maxLines;
        return this;
    }

    public TextLineHelper build() {
        if (minLines < 1) {
            this.minLines = 1;
        }

        if ((maxLines > 30) || (maxLines < 1)) {
            this.maxLines = 30;
        }
        if (maxLines <= minLines) {
            maxLines = minLines + 1;
        }
        if (max2MinDuration < 20) {
            max2MinDuration = 200;
        }
        if (min2MaxDuration < 20) {
            min2MaxDuration = 200;
        }
        return new TextLineHelper(this);
    }
}

}

</pre>

要做一个包裹内容的文本控件,实在是没有好的解决办法,只好用图片代替,我们假设 文字的字号是80sp,测试机是 1920 * 1080的,

  • 纯数字的
Paste_Image.png
  • 中文 + 数字 的
Paste_Image.png
  • 含有英文的
Paste_Image.png
  • 原生的TextView


    Paste_Image.png
  • 代码就在这里,如果您有 更好的方案,可以告诉我

<pre>

package org.alex.wraptextview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

import org.alex.util.LogUtil;

/**
* 作者:Alex
* 时间:2016年10月26日
* 简述:
*/

public class WrapTextView extends View {
protected String text;
protected int textColor;
protected float textSize;
protected Paint paint;
protected int height;
protected int width;
protected float scale;

public WrapTextView(Context context) {
    super(context);
    initView(context, null);
}

public WrapTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initView(context, attrs);
}

public void initView(Context context, AttributeSet attrs) {
    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.WrapView);
    text = typedArray.getString(R.styleable.WrapView_wv_text);
    textSize = typedArray.getDimension(R.styleable.WrapView_wv_textSize, sp2px(14));
    textColor = typedArray.getColor(R.styleable.WrapView_wv_textColor, Color.parseColor("#000000"));
    int language = typedArray.getInteger(R.styleable.WrapView_wv_language, 0);
    LogUtil.e("language = " + language);
    if (language == 0) {
        scale = 0.7F;
    }else if(language == 1){
        scale = 0.9F;
    }else{
        scale = 1.0F;
    }

    typedArray.recycle();
    paint = new Paint();
    paint.setColor(textColor);
    paint.setAntiAlias(true);
    LogUtil.e("textSize = " + textSize + " 14sp = " + sp2px(14));
    paint.setTextSize(textSize);
}

/\*\*
 \* Implement this to do your drawing.
 \*
 \* @param canvas the canvas on which the background will be drawn
 \*/
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (text != null) {
        /\*计算Baseline绘制的起点X轴坐标 ,计算方式:画布宽度的一半 - 文字宽度的一半\*/
        int baseX = (int) (canvas.getWidth() / 2 - paint.measureText(text) / 2);
        /\* 计算Baseline绘制的Y坐标 ,计算方式:画布高度的一半 - 文字总高度的一半\*/
        int baseY = (int) ((canvas.getHeight() / 2) - ((paint.descent() + paint.ascent()) / 2));
        /\*居中画一个文字\*/
        canvas.drawText(text, baseX, baseY, paint);
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    width = MeasureSpec.getSize(widthMeasureSpec);
    height = MeasureSpec.getSize(heightMeasureSpec);
    width = getTextWidth(paint, text);
    height = (int) (getTextHeight(paint) \* getScale());
    setMeasuredDimension(width, height);
}

/\*\*
 \* 0.6-1.0之间,控制文本的留白区域
 \*/
public float getScale() {
    return scale;
}


/\*\*
 \* 获取文字的宽度
 \*
 \* @param paint
 \* @param str
 \* @return
 \*/
public int getTextWidth(Paint paint, String str) {
    int iRet = 0;
    if (str != null && str.length() > 0) {
        int len = str.length();
        float[] widths = new float[len];
        paint.getTextWidths(str, widths);
        for (int j = 0; j < len; j++) {
            iRet += (int) Math.ceil(widths[j]);
        }
    }
    return iRet;
}

/\*\*
 \* 计算文字的高度
 \*
 \* @param paint
 \* @return
 \*/
public int getTextHeight(Paint paint) {
    Paint.FontMetrics fontMetrics = paint.getFontMetrics();
    return (int) Math.ceil(fontMetrics.descent - fontMetrics.ascent);
}

/\*\*
 \* sp转px
 \*/
public int sp2px(float sp) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getContext().getResources().getDisplayMetrics());
}

}


<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="WrapView">
<attr name="wv_text" format="string"/>
<attr name="wv_textSize" format="dimension"/>
<attr name="wv_textColor" format="color"/>
<attr name="wv_language" >
<flag name="num" value="0"/>
<flag name="chinese" value="1"/>
<flag name="english" value="2"/>
</attr>
</declare-styleable>
</resources>
</pre>

TextView | Button 增大文本水平字间距无尽的搜索,找到了一个解决办法,自觉还不错,先看效果图

Paste_Image.png
  • 代码就在这里,如果您有 更好的方案,可以告诉我

<pre>
package github.alex.util;

import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ScaleXSpan;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

/**
* Created by Alex on 2016/6/5.
*/
public class ViewUtil {
/**
* 增大文本水平间距
* @param view TextView | Button | EditText
* @param letterSpace 字间距 [-0.5, 4F] 之间较为合适, 精度为 0.001F
*/
public static void addLetterSpacing(View view, float letterSpace) {
if ((view == null)) {
return;
}
if (view instanceof TextView) {
TextView textView = (TextView) view;
addLetterSpacing(view, textView.getText().toString(), letterSpace);
}
if (view instanceof Button) {
Button button = (Button) view;
addLetterSpacing(view, button.getText().toString(), letterSpace);
}
if (view instanceof EditText) {
EditText editText = (EditText) view;
addLetterSpacing(view, editText.getText().toString(), letterSpace);
}
}

/\*\*
 \* 增大文本水平间距
 \* @param view TextView | Button | EditText
 \* @param letterSpace 字间距 [-0.5, 4F] 之间较为合适, 精度为 0.001F
 \*/
public static void addLetterSpacing(View view, String text, float letterSpace) {
    if ((view == null) || (text == null)) {
        return;
    }
    if (letterSpace == 0F) {
        /\*0 没有效果, 0.001F是最接近0 的 数了,在小一些,也就没有效果了\*/
        letterSpace = 0.001F;
    }
    /\*
    \* 先把 String 拆成 字符数组,在每个字符后面添加一个空格,并对这个进来的空格进行 X轴上 缩放
    \* \*/
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < text.length(); i++) {
        builder.append(text.charAt(i));
        if (i + 1 < text.length()) {
            builder.append("\u00A0");
        }
    }
    SpannableString finalText = new SpannableString(builder.toString());
    for (int i = 1; (builder.toString().length() > 1) && (i < builder.toString().length()); i += 2) {
        finalText.setSpan(new ScaleXSpan(letterSpace), i, i + 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
    }
    if (view instanceof TextView) {
        TextView textView = (TextView) view;
        textView.setText(finalText, TextView.BufferType.SPANNABLE);
    }
}

}

</pre>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值