Android 文字带拼音

这个自定义View可以实现文字带拼音,根据当前VIew长度自动换行,实现一句带拼音文本的多行显示,如果是诗词或者其他多段落场景,可以结合RecyclerView,此View作为一个Item显示一句文本

public class PYTextWrapView extends ViewGroup {

    private static final String TAG = PYTextWrapView.class.getName();
    //子view水平方向padding
    private int mPaddingHor = 0;
    //子view垂直方向padding
    private int mPaddingVer = 20;
    //子view之间的水平间距
    private int mMarginHor = 0;
    //行间距
    private int mMarginVer = 10;
    //最多字个数
    private int mNum = 0;
    private final Context mContext;

    public PYTextWrapView(Context context) {
        super(context);
        mContext = context;
    }

    public PYTextWrapView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAttrs(context, attrs);
        mContext = context;
    }

    public PYTextWrapView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initAttrs(context, attrs);
        mContext = context;
    }

    //获取属性值
    @SuppressLint("CustomViewStyleable")
    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.WordWrapView);
        mPaddingHor = (int) ta.getDimension(R.styleable.WordWrapView_padding_hor, mPaddingHor);
        mPaddingVer = (int) ta.getDimension(R.styleable.WordWrapView_padding_vertical, mPaddingVer);
        mMarginHor = (int) ta.getDimension(R.styleable.WordWrapView_margin_hor, mMarginHor);
        mMarginVer = (int) ta.getDimension(R.styleable.WordWrapView_margin_vertial, mMarginVer);
        ta.recycle();
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount = getChildCount();
        int realWidth = r - l;//实际宽度
        int x = 0;
        // 每一行的宽度
        HashMap<Integer, Integer> lineWidthMap = getAllLineWidth(realWidth);
        int y;
        int rows = 1;
        // 初始化x时,计算左间距
        if (lineWidthMap.get(rows) != null) {
            x = (realWidth - lineWidthMap.get(rows)) / 2;
        }
        //判断累积高度
        for (int i = 0; i < childCount; i++) {
            View view = getChildAt(i);
            //超出宽度或文字有换行符则换行
            TextView tvText = view.findViewById(R.id.tvText);
            boolean isLineFeed = tvText != null && tvText.getText().toString().equals("\n");
            int width = view.getMeasuredWidth();
            int height = view.getMeasuredHeight();
            //不计算换行符的宽度
            if (!isLineFeed) {
                x += width + mMarginHor;
            }
            if (isLineFeed || x > realWidth - mMarginHor) {
                if (i != 0) {
                    x = width + mMarginHor;
                    rows++;
                }
            }
            //当一个子view长度超出父view长度时
            if (x > realWidth - mMarginHor) {
                if (view instanceof TextView) {
                    //判断单个高度
                    TextView tv = (TextView) view;
                    if (mNum == 0) {
                        int wordNum = tv.getText().toString().length();
                        mNum = wordNum * (realWidth - 2 * mMarginHor - 2 * mPaddingHor) / (width - 2 * mPaddingHor) - 1;
                    }
                    String text = tv.getText().toString();
                    text = text.substring(0, mNum) + "...";
                    tv.setText(text);
                }
                x = realWidth - mMarginHor;
                width = realWidth - 2 * mMarginHor;
            }
            y = rows * (height + mMarginVer);
            //有换行符时,重置x位置
            if (isLineFeed) {
                // 初始化x时,计算左间距
                if (lineWidthMap.get(rows) != null) {
                    x = (realWidth - lineWidthMap.get(rows)) / 2;
                }
                view.layout(x, y - height, x, y);
            } else {
                view.layout(x - width, y - height, x, y);
            }
        }
    }

    /**
     * 获取所有行的宽度
     */
    private HashMap<Integer, Integer> getAllLineWidth(int realWidth) {
        HashMap<Integer, Integer> widthMap = new HashMap();
        try {
            int maxWidth = 0;
            int childCount = getChildCount();
            int x = 0;
            int y;
            int rows = 1;
            //判断累积高度
            for (int i = 0; i < childCount; i++) {
                View view = getChildAt(i);
                //超出宽度或文字有换行符则换行
                TextView tvText = view.findViewById(R.id.tvText);
                boolean isLineFeed = tvText != null && tvText.getText().toString().equals("\n");
                int width = view.getMeasuredWidth();
                int height = view.getMeasuredHeight();
                //不计算换行符的宽度
                if (!isLineFeed) {
                    x += width + mMarginHor;
                    maxWidth = Math.max(x, maxWidth);
                    widthMap.put(rows, maxWidth);
                }
                if (isLineFeed || x > realWidth - mMarginHor) {
                    if (i != 0) {
                        x = width + mMarginHor;
                        rows++;
                    }
                }
                //当一个子view长度超出父view长度时
                if (x > realWidth - mMarginHor) {
                    if (view instanceof TextView) {
                        //判断单个高度
                        TextView tv = (TextView) view;
                        if (mNum == 0) {
                            int wordNum = tv.getText().toString().length();
                            mNum = wordNum * (realWidth - 2 * mMarginHor - 2 * mPaddingHor) / (width - 2 * mPaddingHor) - 1;
                        }
                        String text = tv.getText().toString();
                        text = text.substring(0, mNum) + "...";
                        tv.setText(text);
                    }
                    x = realWidth - mMarginHor;
                    width = realWidth - 2 * mMarginHor;
                }
                y = rows * (height + mMarginVer);
                //有换行符时,重置x位置
                if (isLineFeed) {
                    x = 0;
                    maxWidth = 0;
                    view.layout(x, y - height, x, y);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return widthMap;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //所有行最大的宽度
        int maxWidth = 0;
        int x = 0;
        int y = 0;
        int rows = 1;
        // 控件最大宽度
        int realWith = MeasureSpec.getSize(widthMeasureSpec);
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);
            child.setPadding(mPaddingHor, mPaddingVer, mPaddingHor, mPaddingVer);
            child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
            int width = child.getMeasuredWidth();
            int height = child.getMeasuredHeight();
            try {
                TextView tvText = child.findViewById(R.id.tvText);
                //超出宽度或文字有换行符则换行
                boolean isLineFeed = tvText != null && tvText.getText().toString().equals("\n");
                //不计算换行符的宽度
                if (!isLineFeed) {
                    x += width + mMarginHor;
                }
                //判断一下最大宽度
                maxWidth = Math.max(x, maxWidth);
                //最后一行时不需要换行
                if ((isLineFeed && i != childCount - 1) || x > realWith - mMarginHor) {
                    if (i != 0) {
                        x = 0;
                        rows++;
                    }
                }
                y = rows * (height + mMarginVer);
            } catch (Exception e) {
                Logger.e(TAG, e.getMessage());
            }
        }
        if (maxWidth > realWith) {
            setMeasuredDimension(realWith, y + mMarginVer);
        } else {
            realWith = maxWidth + mMarginHor;
            setMeasuredDimension(realWith, y + mMarginVer);
        }
    }

    @SuppressLint("InflateParams")
    public void setData(List<PYTextWrapper> pyTextWrapperList) {
        if (pyTextWrapperList == null || pyTextWrapperList.isEmpty()) {
            return;
        }
        removeAllViews();
        //整句是否无拼音 解决无拼音时高度问题
        boolean hasNoPy = true;
        for (PYTextWrapper pyTextWrapper : pyTextWrapperList) {
            if (!TextUtils.isEmpty(pyTextWrapper.mPY)) {
                hasNoPy = false;
            }
        }
        for (PYTextWrapper pyTextWrapper : pyTextWrapperList) {
            View itemPYText = LayoutInflater.from(mContext).inflate(R.layout.item_pic_recite_ping_ying_text, null);
            setPYData(itemPYText, pyTextWrapper, hasNoPy);
            addView(itemPYText);
        }
    }

    private void setPYData(View view, PYTextWrapper pyTextWrapper, Boolean hasNoPy) {
        TextView pyText = view.findViewById(R.id.tvPY);
        TextView tvText = view.findViewById(R.id.tvText);
        Typeface typeFace = Typeface.createFromAsset(UIUtils.getAppContext().getAssets(), "fonts/cn_py.ttf");
        pyText.setTypeface(typeFace);
        pyText.setText(pyTextWrapper.mPY);
        tvText.setText(pyTextWrapper.mText);
        if (hasNoPy && TextUtils.isEmpty(pyTextWrapper.mPY)) {
            pyText.setVisibility(GONE);
        } else {
            pyText.setVisibility(VISIBLE);
        }
        pyText.setTextColor(UIUtils.getColor(mTextColor));
        tvText.setTextColor(UIUtils.getColor(mTextColor));
    }

    private int mTextColor = R.color.color_555555;

    /**
     * 设置文字颜色
     */
    public void setTextColor(int textColor) {
        mTextColor = textColor;
    }
}

涉及的布局 item_pic_recite_ping_ying_text

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tvPY"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:gravity="center"
        android:minWidth="30dp"
        android:textColor="@color/color_888888"
        android:textSize="9sp" />

    <TextView
        android:id="@+id/tvText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="0.5dp"
        android:gravity="center"
        android:minWidth="30dp"
        android:textColor="@color/color_888888"
        android:textSize="15sp" />
</LinearLayout>

数据类的定义

public class PYTextWrapper implements Serializable {
    //拼音
    public String mPY;
    //文字
    public String mText;

    public PYTextWrapper(String mPY, String mText) {
        this.mPY = mPY;
        this.mText = mText;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值