可伸缩TextView和TextView显示错位问题

开发中下面这种文字显示是不是熟悉。让我们来看一下是怎么实现的。【该文参考链接结尾呈现】

1.首先使用一个可伸缩的自定义TextView-----StretchyTextView .java

package demo.myapplication;

import android.annotation.SuppressLint;
import android.content.Context;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

/**
 * 可伸展的文本显示布局
 *
 * @author jan
 */
public class StretchyTextView extends LinearLayout implements View.OnClickListener {
    //默认显示的最大行数
    private static final int DEFAULT_MAX_LINE_COUNT = 2;
    //当前展开标志显示的状态
    private static final int SPREADTEXT_STATE_NONE = 0;
    private static final int SPREADTEXT_STATE_RETRACT = 1;
    private static final int SPREADTEXT_STATE_SPREAD = 2;

    private TextView contentText;
    private TextView operateText;
    private LinearLayout bottomTextLayout;

    private String shrinkup;
    private String spread;
    private int mState;
    private boolean flag = false;
    private int maxLineCount = DEFAULT_MAX_LINE_COUNT;
    private InnerRunnable runable;

    public StretchyTextView(Context context) {
        this(context, null);
    }

    public StretchyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
//        shrinkup = context.getString(R.string.retract);
//        spread = context.getString(R.string.spread);
        shrinkup = "展开";
        spread = "收起";
        View view = inflate(context, R.layout.stretchy_text_layout, this);
        view.setPadding(0, -1, 0, 0);
        contentText = (TextView) view.findViewById(R.id.content_textview);
        operateText = (TextView) view.findViewById(R.id.bottom_textview);
        bottomTextLayout = (LinearLayout) view.findViewById(R.id.bottom_text_layout);
        setBottomTextGravity(Gravity.LEFT);
        operateText.setOnClickListener(this);
        runable = new InnerRunnable();
    }

    @Override
    public void onClick(View v) {
        flag = false;
        requestLayout();
    }

    public final void setContent(CharSequence charSequence) {
        contentText.setText(charSequence, TextView.BufferType.NORMAL);
        mState = SPREADTEXT_STATE_SPREAD;
        Log.d("setContent", "count lines=" + contentText.getLineCount() + ",flag=" + flag);
        flag = false;
        requestLayout();
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (!flag) {
            flag = !flag;
            if (contentText.getLineCount() <= DEFAULT_MAX_LINE_COUNT) {
                mState = SPREADTEXT_STATE_NONE;
                operateText.setVisibility(View.GONE);
                contentText.setMaxLines(DEFAULT_MAX_LINE_COUNT + 1);
            } else {
                post(runable);
            }
        }
    }

    class InnerRunnable implements Runnable {
        @Override
        public void run() {
            if (mState == SPREADTEXT_STATE_SPREAD) {
                contentText.setMaxLines(maxLineCount);
                operateText.setVisibility(View.VISIBLE);
                operateText.setText(spread);
                mState = SPREADTEXT_STATE_RETRACT;
            } else if (mState == SPREADTEXT_STATE_RETRACT) {
                contentText.setMaxLines(Integer.MAX_VALUE);
                operateText.setVisibility(View.VISIBLE);
                operateText.setText(shrinkup);
                mState = SPREADTEXT_STATE_SPREAD;
            }
        }
    }

    public void setMaxLineCount(int maxLineCount) {
        this.maxLineCount = maxLineCount;
    }

    public void setContentTextColor(int color) {
        this.contentText.setTextColor(color);
    }

    public void setContentTextSize(float size) {
        this.contentText.setTextSize(size);
    }

    /**
     * 内容字体加粗
     */
    public void setContentTextBold() {
        TextPaint textPaint = contentText.getPaint();
        textPaint.setFakeBoldText(true);
    }

    /**
     * 设置展开标识的显示位置
     *
     * @param gravity
     */
    public void setBottomTextGravity(int gravity) {
        bottomTextLayout.setGravity(gravity);
    }
}

效果图如下,发现文字显示错乱,右侧没有对齐,这是万万不行的:



2.解决文字显示错乱的问题,试了很多都不理想,后来发现一个自定义textview---MyTextView.java。自我感觉比较靠谱,看一下效果。

最后附上源码:

stretchy_text_layout

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

    <demo.myapplication.MyTextView
        android:id="@+id/content_textview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="3dip"
        android:ellipsize="end"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:fadeScrollbars="false"
        android:gravity="center_vertical|left"
        android:textColor="#ff000000"
        android:textSize="16dip" />

    <LinearLayout
        android:id="@+id/bottom_text_layout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="right"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/bottom_textview"
            android:layout_width="match_parent"
            android:layout_height="27dp"
            android:layout_marginTop="8dip"
            android:background="#e9e7e7"
            android:gravity="center"
            android:padding="2dp"
            android:singleLine="true"
            android:textColor="#808080"
            android:textSize="15dip"
            android:visibility="visible" />
    </LinearLayout>
</LinearLayout>

MyTextView.java

/**
 * @author lhx
 * @Date 9/8/15
 * textView遇到标点换行问题
 */
public class MyTextView extends TextView {

    private int mLineY;
    private int mViewWidth;

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

    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
                            int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }

    @Override
    protected void onDraw(Canvas Canvas) {
        TextPaint paint = getPaint();
        paint.setColor(getCurrentTextColor());
        paint.drawableState = getDrawableState();
        mViewWidth = getMeasuredWidth();
        String text = getText().toString();
        mLineY = 0;
        mLineY += getTextSize();
        Layout layout = getLayout();

        // layout.getLayout()在4.4.3出现NullPointerException
        if (layout == null) {
            return;
        }

        Paint.FontMetrics fm = paint.getFontMetrics();

        int textHeight = (int) (Math.ceil(fm.descent - fm.ascent));
        textHeight = (int) (textHeight * layout.getSpacingMultiplier() + layout
                .getSpacingAdd());
        //解决了最后一行文字间距过大的问题
        for (int i = 0; i < layout.getLineCount(); i++) {
            int lineStart = layout.getLineStart(i);
            int lineEnd = layout.getLineEnd(i);
            float width = StaticLayout.getDesiredWidth(text, lineStart,
                    lineEnd, getPaint());
            String line = text.substring(lineStart, lineEnd);

            if(i < layout.getLineCount() - 1) {
                if (needScale(line)) {
                    drawScaledText(Canvas, lineStart, line, width);
                } else {
                    Canvas.drawText(line, 0, mLineY, paint);
                }
            } else {
                Canvas.drawText(line, 0, mLineY, paint);
            }
            mLineY += textHeight;
        }
    }

    private void drawScaledText(Canvas Canvas, int lineStart, String line,
                                float lineWidth) {
        float x = 0;
        if (isFirstLineOfParagraph(lineStart, line)) {
            String blanks = "  ";
            Canvas.drawText(blanks, x, mLineY, getPaint());
            float bw = StaticLayout.getDesiredWidth(blanks, getPaint());
            x += bw;

            line = line.substring(3);
        }

        int gapCount = line.length() - 1;
        int i = 0;
        if (line.length() > 2 && line.charAt(0) == 12288
                && line.charAt(1) == 12288) {
            String substring = line.substring(0, 2);
            float cw = StaticLayout.getDesiredWidth(substring, getPaint());
            Canvas.drawText(substring, x, mLineY, getPaint());
            x += cw;
            i += 2;
        }

        float d = (mViewWidth - lineWidth) / gapCount;
        for (; i < line.length(); i++) {
            String c = String.valueOf(line.charAt(i));
            float cw = StaticLayout.getDesiredWidth(c, getPaint());
            Canvas.drawText(c, x, mLineY, getPaint());
            x += cw + d;
        }
    }

    private boolean isFirstLineOfParagraph(int lineStart, String line) {
        return line.length() > 3 && line.charAt(0) == ' '
                && line.charAt(1) == ' ';
    }

    private boolean needScale(String line) {
        if (line == null || line.length() == 0) {
            return false;
        } else {
            return line.charAt(line.length() - 1) != '\n';
        }
    }

}

StretchyTextView .java

/**
 * 可伸展的文本显示布局
 *
 * @author jan
 */
public class StretchyTextView extends LinearLayout implements View.OnClickListener {
    //默认显示的最大行数
    private static final int DEFAULT_MAX_LINE_COUNT = 2;
    //当前展开标志显示的状态
    private static final int SPREADTEXT_STATE_NONE = 0;
    private static final int SPREADTEXT_STATE_RETRACT = 1;
    private static final int SPREADTEXT_STATE_SPREAD = 2;

    private MyTextView contentText;
    private TextView operateText;
    private LinearLayout bottomTextLayout;

    private String shrinkup;
    private String spread;
    private int mState;
    private boolean flag = false;
    private int maxLineCount = DEFAULT_MAX_LINE_COUNT;
    private InnerRunnable runable;

    public StretchyTextView(Context context) {
        this(context, null);
    }

    public StretchyTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
//        shrinkup = context.getString(R.string.retract);
//        spread = context.getString(R.string.spread);
        shrinkup = "展开";
        spread = "收起";
        View view = inflate(context, R.layout.stretchy_text_layout, this);
        view.setPadding(0, -1, 0, 0);
        contentText = (MyTextView) view.findViewById(R.id.content_textview);
        operateText = (TextView) view.findViewById(R.id.bottom_textview);
        bottomTextLayout = (LinearLayout) view.findViewById(R.id.bottom_text_layout);
        setBottomTextGravity(Gravity.LEFT);
        operateText.setOnClickListener(this);
        runable = new InnerRunnable();
    }

    @Override
    public void onClick(View v) {
        flag = false;
        requestLayout();
    }

    public final void setContent(CharSequence charSequence) {
        contentText.setText(charSequence, TextView.BufferType.NORMAL);
        mState = SPREADTEXT_STATE_SPREAD;
        Log.d("setContent", "count lines=" + contentText.getLineCount() + ",flag=" + flag);
        flag = false;
        requestLayout();
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (!flag) {
            flag = !flag;
            if (contentText.getLineCount() <= DEFAULT_MAX_LINE_COUNT) {
                mState = SPREADTEXT_STATE_NONE;
                operateText.setVisibility(View.GONE);
                contentText.setMaxLines(DEFAULT_MAX_LINE_COUNT + 1);
            } else {
                post(runable);
            }
        }
    }

    class InnerRunnable implements Runnable {
        @Override
        public void run() {
            if (mState == SPREADTEXT_STATE_SPREAD) {
                contentText.setMaxLines(maxLineCount);
                operateText.setVisibility(View.VISIBLE);
                operateText.setText(spread);
                mState = SPREADTEXT_STATE_RETRACT;
            } else if (mState == SPREADTEXT_STATE_RETRACT) {
                contentText.setMaxLines(Integer.MAX_VALUE);
                operateText.setVisibility(View.VISIBLE);
                operateText.setText(shrinkup);
                mState = SPREADTEXT_STATE_SPREAD;
            }
        }
    }

    public void setMaxLineCount(int maxLineCount) {
        this.maxLineCount = maxLineCount;
    }

    public void setContentTextColor(int color) {
        this.contentText.setTextColor(color);
    }

    public void setContentTextSize(float size) {
        this.contentText.setTextSize(size);
    }

    /**
     * 内容字体加粗
     */
    public void setContentTextBold() {
        TextPaint textPaint = contentText.getPaint();
        textPaint.setFakeBoldText(true);
    }

    /**
     * 设置展开标识的显示位置
     *
     * @param gravity
     */
    public void setBottomTextGravity(int gravity) {
        bottomTextLayout.setGravity(gravity);
    }


activity_mian.xml

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

    <demo.myapplication.StretchyTextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"></demo.myapplication.StretchyTextView>
</LinearLayout>


MianActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        StretchyTextView mTextView= (StretchyTextView) findViewById(R.id.textView);
        mTextView.setContent("近些年来,越来越多的行业开始和互联网结合," +
                "诞生了越来越多的互联网创业公司。互联网创业公司需要面对许多的不确定因素" +
                "。如果你和你的小伙伴们够幸运 ,你们的公司可能会在几个星期之内让用户数、商品数、" +
                "订单量增长几十倍上百倍。一次促销可能会带来平时几十倍的访问流量," +
                "一次秒杀活动可能会吸引平时数百倍的访问用户。这对公司自然是极大的好事," +
                "说明产品得到认可,公司未来前景美妙。");
        mTextView.setMaxLineCount(6);  //最大行数
    }
}



参考链接:http://blog.csdn.net/jdsjlzx/article/details/50616227

                  http://blog.csdn.net/qq_29443203/article/details/54141426




猜你喜欢

转载自blog.csdn.net/Liu_Liu_Q/article/details/78077421
今日推荐