2.具体实现
但从实现效果方面来看,只用简单定义必要view即可,后变为了方便扩展使用和挪用,又对整个布局进行封装,方便直接使用。
2.1 通过多个布局组合实现
第一想法当然是用多个View组合来实现。那么久定义一个LinearLayout布局分别嵌套TextView和ImageView来做。
大概步骤:
- 定义布局,垂直的线性LinearLayout布局、TextView和ImageView。 在layout中定义基本组件。
- 设置TextView的高度为指定行数*行高。 不使用maxLine的原因是maxLine会控制显示文本的行数,不方便后边使用动画展开全部内容。因此这里TextView的高度也因该为wrap_content。
- 给整个布局添加点击事件,绑定动画。 点击时,若TextView未展开则展开至其实际高度,imageView 旋转;否则回缩至 指定行数*行高 , imageView 旋转缩回。
开始编写代码:
1.在xml中定义布局:
<LinearLayout android:id="@+id/description_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingLeft="12dip" android:paddingRight="12dip" android:paddingTop="5dip" > <TextView android:id="@+id/description_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="@android:color/black" android:textSize="18dip" > </TextView> <ImageView android:id="@+id/expand_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:paddingBottom="5dip" android:paddingLeft="5dip" android:paddingRight="5dip" android:paddingTop="5dip" android:src="@drawable/text_ic_expand" android:visibility="gone" /> </LinearLayout>2.首先在activity中定义并初始化这些view:
public class MainActivity extends Activity { TextView descriptionView; View layoutView ,expandView; //LinearLayout布局和ImageView int maxDescripLine = 3; //TextView默认最大展示行数 //在OnCreate中初始化 { layoutView = findViewById(R.id.description_layout); descriptionView = (TextView)findViewById(R.id.description_view); expandView = findViewById(R.id.expand_view); }}3.然后设置textview显示文本,再根据默认展示行数设置其高度,并根据其是否已完全显示(当前展示行数是否大于等于实际行数)来判断需不需要点击更多按钮。
//设置文本 descriptionView.setText(getText(R.string.content)); //descriptionView设置默认显示高度 descriptionView.setHeight(descriptionView.getLineHeight() * maxDescripLine); //根据高度来判断是否需要再点击展开 descriptionView.post(new Runnable() { @Override public void run() { expandView.setVisibility(descriptionView.getLineCount() > maxDescripLine ? View.VISIBLE : View.GONE); } });因为textView设置的是wrap_content,所以会显示实际高度和行数,这里根据maxDescripLine来设置其高度。
layoutView.setOnClickListener(new View.OnClickListener() { boolean isExpand;//是否已展开的状态 @Override public void onClick(View v) { isExpand = !isExpand; descriptionView.clearAnimation();//清楚动画效果 final int deltaValue;//默认高度,即前边由maxLine确定的高度 final int startValue = descriptionView.getHeight();//起始高度 int durationMillis = 350;//动画持续时间 if (isExpand) {/*** 折叠动画* 从实际高度缩回起始高度*/deltaValue = descriptionView.getLineHeight() * descriptionView.getLineCount() - startValue;RotateAnimation animation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);animation.setDuration(durationMillis);animation.setFillAfter(true);expandView.startAnimation(animation); } else {/*** 展开动画* 从起始高度增长至实际高度*/deltaValue = descriptionView.getLineHeight() * maxDescripLine - startValue;RotateAnimation animation = new RotateAnimation(180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);animation.setDuration(durationMillis);animation.setFillAfter(true);expandView.startAnimation(animation); } Animation animation = new Animation() {protected void applyTransformation(float interpolatedTime, Transformation t) { //根据ImageView旋转动画的百分比来显示textview高度,达到动画效果descriptionView.setHeight((int) (startValue + deltaValue * interpolatedTime));} }; animation.setDuration(durationMillis); descriptionView.startAnimation(animation); } });至此,通过布局已经实现了我们想要的效果。具体代码参见代码示例 的第一部分。
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="MoreTextStyle"> <attr name="textSize" format="dimension"/> <attr name="textColor" format="color"/> <attr name="maxLine" format="integer" /> <attr name="text" format="string" /> </declare-styleable></resources>2.自定义MoreTextView并获取这些属性的值
public class MoreTextView extends LinearLayout{ protected TextView contentView; //文本正文 protected ImageView expandView; //展开按钮 //对应styleable中的属性 protected int textColor;protected float textSize; protected int maxLine; protected String text; //默认属性值 public int defaultTextColor = Color.BLACK; public int defaultTextSize = 12; public int defaultLine = 3; //....实现部分略}(2)MoreTextView的构造方法:
public MoreTextView(Context context, AttributeSet attrs) { super(context, attrs); initalize();initWithAttrs(context, attrs);bindListener(); }这三个方法简单说明下:
//初始化并添加Viewprotected void initalize() { setOrientation(VERTICAL); //设置垂直布局 setGravity(Gravity.RIGHT); //右对齐 //初始化textView并添加 contentView = new TextView(getContext()); addView(contentView, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); //初始化ImageView并添加 expandView = new ImageView(getContext()); int padding = dip2px(getContext(), 5); expandView.setPadding(padding, padding, padding, padding); expandView.setImageResource(R.drawable.text_ic_expand); LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); addView(expandView, llp);取值并设置这部分有必要将一下。我们利用TypedArray从定义的styleable中取出属性值,赋给我们定义好的类的属性变量。记得取完之后调用recycle()回收释放。
protected void initWithAttrs(Context context, AttributeSet attrs) { TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.MoreTextStyle);int textColor = a.getColor(R.styleable.MoreTextStyle_textColor,defaultTextColor); //取颜色值,默认defaultTextColor textSize = a.getDimensionPixelSize(R.styleable.MoreTextStyle_textSize, defaultTextSize);//取颜字体大小,默认defaultTextSize maxLine = a.getInt(R.styleable.MoreTextStyle_maxLine, defaultLine);//取颜显示行数,默认defaultLine text = a.getString(R.styleable.MoreTextStyle_text);//取文本内容 //绑定到textView bindTextView(textColor,textSize,maxLine,text); a.recycle();//回收释放 } //绑定到textViewprotected void bindTextView(int color,float size,final int line,String text){ contentView.setTextColor(color); contentView.setTextSize(TypedValue.COMPLEX_UNIT_PX,size); contentView.setText(text); contentView.setHeight(contentView.getLineHeight() * line); post(new Runnable() {//前面已讲,不再赘述 @Override public void run() { expandView.setVisibility(contentView.getLineCount() > line ? View.VISIBLE : View.GONE); } }); }最后设置点击事件。
//点击展开与折叠,不再赘述 protected void bindListener(){ setOnClickListener(new View.OnClickListener() { boolean isExpand; @Override public void onClick(View v) { isExpand = !isExpand; contentView.clearAnimation(); final int deltaValue; final int startValue = contentView.getHeight(); int durationMillis = 350; if (isExpand) {deltaValue = contentView.getLineHeight() * contentView.getLineCount() - startValue;RotateAnimation animation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);animation.setDuration(durationMillis);animation.setFillAfter(true);expandView.startAnimation(animation); } else {deltaValue = contentView.getLineHeight() * maxLine - startValue;RotateAnimation animation = new RotateAnimation(180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);animation.setDuration(durationMillis);animation.setFillAfter(true);expandView.startAnimation(animation); } Animation animation = new Animation() {protected void applyTransformation(float interpolatedTime, Transformation t) {contentView.setHeight((int) (startValue + deltaValue * interpolatedTime));} }; animation.setDuration(durationMillis); contentView.startAnimation(animation); } }); }另外,定义几个方法方便外部调用(获取文本TextView,直接设置文本内容),同时还定义了一个dip转像素的静态方法。
public TextView getTextView(){ return contentView; } public void setText(CharSequence charSequence){ contentView.setText(charSequence); } public static int dip2px(Context context, float dipValue){final float scale = context.getResources().getDisplayMetrics().density; return (int)(dipValue * scale + 0.5f);}其实到这里,我们的自定义多文本折叠展开MoreTextView已经完成了。如何使用呢?
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:more="http://schemas.android.com/apk/res/com.qiao.moretext" android:id="@+id/root" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" android:orientation="vertical" > <com.qiao.moretext.MoreTextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="5dip"more:textColor="@android:color/black" more:textSize="18dip" more:maxLine="3" more:text="@string/content"/></LinearLayout>在java中直接定义使用
MoreTextView content = new MoreTextView(MainActivity.this, null); content.setText(getText(R.string.content)); //然后addview到你要添加的地方 当然,聪明如你,可肯定知道怎么定义另外的构造方法来简单实用啦。 –> MoreTextView(Context context){ //使用默认值直接初始化 bindTextView(); }3.综述