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