天天看点

自定义TextView解决超长文字显示的问题

很多时候由于手机屏幕的显示,TextView单行没法显示完全内容。如下所示:

自定义TextView解决超长文字显示的问题

当点击3个点的时候,文字就会展开:

自定义TextView解决超长文字显示的问题

对于这个需求,可以使用一个LinearLayout,orientation是horizontal,有两个TextView,一个显示内容,一个显示...

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@+id/root" >

    <TextView
        android:id="@+id/mainText"
        android:layout_width="wrap_content"
        android:textSize="25sp"
        android:textColor="#000000"
        android:maxLines="10"
        android:layout_height="wrap_content"
        android:gravity="center_vertical|left"
         />
    <TextView
        android:id="@+id/mainDots"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="25sp"
        android:textColor="#000000"
        android:gravity="center_vertical"
        android:text="..."
        android:linksClickable="true"
        android:visibility="gone"
        android:textAppearance="?android:attr/textAppearanceMedium"
       />

</merge>
           

在代码中,首先在在资源文件中声明这个view的属性:

<declare-styleable name="ClickableTextView">
        <attr name="text" format="string" />
        <attr name="textStyle" format="string" />
        <attr name="textSize" format="dimension" />
        <attr name="textColor" format="color" />
        <attr name="maxLines" format="integer" min="0" />
        <attr name="textGravity" format="enum">
            <enum name="left" value="0" />
            <enum name="center" value="1" />
            <enum name="right" value="2" />
        </attr>
    </declare-styleable>
           

显示在layout的时候可以这么写

<com.example.clickabletextview.ClickableTextView  xmlns:am="http://schemas.android.com/apk/res/com.example.clickabletextview"
        android:id="@+id/textview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        am:text="aadsjklfsjflsdfjslkfsdfajfdsafnasjifnsdjiafnsifjnsdifjsndfsdjifnsdfjnsdsdjfsfdsfdsffjsdflksdf"
        am:textSize ="20sp"/>
           

在ClickableTextVIew这个类里,我们先取到xml的属性:

public ClickableTextView(Context context, AttributeSet attrs) {
		super(context, attrs);
		TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.ClickableTextView, 0, 0);
		int n = a.getIndexCount();
		for (int i = 0; i < n; i++) {
			int attr = a.getIndex(i);
			switch (attr) {
			case R.styleable.ClickableTextView_textSize:
				mTextSizePixel = a.getDimension(attr, DEFAULT_TEXT_SIZE);
				break;
			case R.styleable.ClickableTextView_textColor:
				mTextColor = a.getColor(attr, DEFAULT_TEXT_COLOR);
				break;
			
			case R.styleable.ClickableTextView_textStyle:
				mTextStyle = a.getString(R.styleable.ClickableTextView_textStyle);
				break;
			case R.styleable.ClickableTextView_text:
				defaultText = a.getString(R.styleable.ClickableTextView_text);
				break;
			}
		}
		a.recycle();
		
		init(context);
	}
           

然后把这些属性set给TextView,当赋值TextSize的时候,为了适配很多分辨率,我们要采用mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSizePixel)来赋值

private void init(Context context) {
		if(mRoot == null) {
			mRoot = inflate(context, R.layout.customtext, this);
		}
		mRoot.setFocusable(true);
		mRoot.setFocusableInTouchMode(true);
		
		mDots = (TextView) findViewById(R.id.mainDots);
		mDots.setVisibility(View.GONE);
		mDots.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSizePixel);
		//mDots.setTextSize(mTextSize);
		mDots.setTextColor(mTextColor);
		mDots.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);	//
		mDots.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				if (!mExpanded)
					onDotsClicked();
			}
		});
		
		mText = (TextView) findViewById(R.id.mainText);
		if (BOLDSTYLE.equals(mTextStyle)) {
			mText.getPaint().setFakeBoldText(true);
		}
		mText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSizePixel);
		//mText.setTextSize(mTextSize);
		mText.setTextColor(mTextColor);
		
	}
           

在onSizeChange的时候,这个view已经得到宽度了,这时我们把文字放入textview中:

@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		int width = w;
		mTextWidth = width -3*getDotsWidth();
		LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mTextWidth, RelativeLayout.LayoutParams.WRAP_CONTENT);
		mText.setSingleLine(true);
		mText.setLayoutParams(params);
		if(!TextUtils.isEmpty(defaultText)) {
			setText(defaultText);
		}
	}

	public void setWidth(int paddingLeft){
		if(mIsSetWidth){
			return;
		}
		mIsSetWidth = true;
		this.mTextWidth = (mTextWidth-paddingLeft);
		LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(mTextWidth, RelativeLayout.LayoutParams.WRAP_CONTENT);
		mText.setSingleLine(true);
		mText.setLayoutParams(params);
	}
	
	private int getDotsWidth() {
		TextPaint mPaint = mDots.getPaint();
		return (int)mPaint.measureText(mDots.getText().toString());
	}

	public void setText(String text) {
		if(mIsClicked){
			return;
		}
		if(text == null) {
			text = "";
		}
		mContent = text;
		mExpanded = false;
		mOriText = text;
		mText.setText(mContent);
		mText.measure(getMeasuredWidth(), getMeasuredHeight());
		mDots.setVisibility(View.GONE);
		String newText = getTruncText(mContent, mText);
		if (newText.length() < mText.length()) {
			mDots.setVisibility(View.VISIBLE);
			mText.measure(getMeasuredWidth(), getMeasuredHeight());
			newText = getTruncText(mContent, mText);
			mText.setText(newText);
		}
	}<pre name="code" class="java"><span style="white-space:pre">	</span>private String getTruncText(String text, TextView view) {
		final Paint textPaint = view.getPaint();
		final int numChar = textPaint.breakText(text, true, mTextWidth, null);
		return text.substring(0, numChar);
	}
           

这个原理是给TextView设置一个固定的宽度,然后让他加载文字,measure他,然后通过得到view.getPaint()得到这个view的绘制信息,然后可以得到这个TextView可以放多少个字符,得到之后跟原来的字符数对比,如果原来的字符多于可以放的下的字符,就显示...

可以在http://download.csdn.net/detail/baidu_nod/7521021下载代码