前言
公司的項目中用到了一個TextView 的點擊加載更多,這個時候一般的Textview滿足不了這個要求了就需要我們自定義TextView,今天也在這個地方總結和寫一下自定義的TextView點擊顯示更多。
名言
想而奮進的過程,其意義遠大於未知的結果。
我們這裏就先來看看效果圖吧。
接下來我們來看看是怎麼實現的,全部代碼會在文章底部給出。
第一步:繼承了LinearLayout重寫了3個構造函數
public class MyTextview extends LinearLayout {
public MyTextview(Context context) {
super(context);
}
public MyTextview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyTextview(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
第二步:寫出我們需要的自定義控件
public void initView() {
setOrientation(VERTICAL);
setGravity(Gravity.RIGHT);
int padding = dip2px(getContext(), 10);
textView = new TextView(getContext());
//行間距
textView.setLineSpacing(3f, 1f);
addView(textView, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
img = new ImageView(getContext());
img.setPadding(padding, padding, padding, padding);
//imageview設置圖片
img.setImageResource(R.mipmap.textimg);
LayoutParams llp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
addView(img, llp);
}
第三步:自定義控件的屬性
在res—>values—>創建attrs.xml
如圖
然後在attrs文件中寫上我們的自定義屬性
textSize字體大小
textColor字體顏色
maxLine最大行數
text文字
<resources>
<declare-styleable name="MyTextStyle">
<attr name="textSize" format="dimension" />
<attr name="textColor" format="color" />
<attr name="maxLine" format="integer" />
<attr name="text" format="string" />
</declare-styleable>
</resources>
第四步:在自定義view的代碼中引入自定義屬性,修改構造函數
public void initAttrs(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyTextStyle);
textColor = typedArray.getColor(R.styleable.MyTextStyle_textColor, defaultTextColor);
textSize = typedArray.getDimensionPixelSize(R.styleable.MyTextStyle_textSize, defaultTextSize);
maxLine = typedArray.getInt(R.styleable.MyTextStyle_maxLine, defaultLine);
text = typedArray.getString(R.styleable.MyTextStyle_text);
setMyView(textColor, textSize, maxLine, text);
//用完 回收一下
typedArray.recycle();
}
這個地方context通過調用obtainStyledAttributes方法來獲取一個TypeArray,然後由該TypeArray來對屬性進行設置。設置完以後必須要回收一下typedArray.recycle();
第五步:自定義的屬性引入進來了我們就要設置在我們TextView上面啊。
protected void setMyView(int color, float size, final int line, String text) {
//文本設置顏色
textView.setTextColor(color);
//字體大小
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
//設置文字
textView.setText(text);
//設置TextView的高度
textView.setHeight(textView.getLineHeight() * line);
//線程更新UI
post(new Runnable() {
@Override
public void run() {
if (textView.getLineCount() > line) {
img.setVisibility(VISIBLE);
} else {
img.setVisibility(GONE);
}
}
});
}
看看這一段
textView.getLineHeight()* line
獲取textview每一行的高度*有多少行,就是我們TextView的高度
public void run() {
if (textView.getLineCount() > line) {
img.setVisibility(VISIBLE);
} else {
img.setVisibility(GONE);
}
}
這個地方需要在線程中來更新UI,假如textView.getLineCount()(textview的總的行數大於了初始行數)圖片就顯示出來,反之不顯示。
第六步:監聽
protected void textListener() {
setOnClickListener(new OnClickListener() {
boolean isGo;
@Override
public void onClick(View v) {
isGo = !isGo;
textView.clearAnimation();
//相差的高度
final int deltaValue;
//初始的高度
final int startValue = textView.getHeight();
//動畫播放的時間
int duration = 1000;
if (isGo) {
//Image圖片打開的動畫
deltaValue = textView.getLineHeight() * textView.getLineCount() - startValue;
RotateAnimation animation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animation.setDuration(duration);
animation.setFillAfter(true);
img.startAnimation(animation);
} else {
//Image圖片關閉的動畫
deltaValue = textView.getLineHeight() * maxLine - startValue;
RotateAnimation animation = new RotateAnimation(180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animation.setDuration(duration);
animation.setFillAfter(true);
img.startAnimation(animation);
}
//打開或者關閉的時候textview下面的展開動畫
Animation animation = new Animation() {
protected void applyTransformation(float interpolatedTime, Transformation t) {
textView.setHeight((int) (startValue + deltaValue * interpolatedTime));
}
};
//這裏給這個設置了一個回彈效果
animation.setInterpolator(new BounceInterpolator());
animation.setDuration(duration);
textView.startAnimation(animation);
}
});
}
第七步:把設置文字暴露外部
public void setText(CharSequence charSequence) {
textView.setText(charSequence);
}
這裏就差不多就完成了,然後我們再來看看xml文件中
<com.example.beiduo.testmytext.MyTextview
xmlns:more="http://schemas.android.com/apk/res-auto"
android:background="#ffdfdf"
android:id="@+id/tv"
android:padding="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
more:maxLine="2"
more:text=""
more:textColor="#434343"
more:textSize="20sp"></com.example.beiduo.testmytext.MyTextview>
xmlns:more="http://schemas.android.com/apk/res-auto"這句話是相當重要的,沒有這句話你是用不起你自己自定義的屬性的more可以隨你自己改,想改什麼改什麼。
more:maxLine="2" maxline是初始的最大行數
MainActivity中
public class MainActivity extends AppCompatActivity {
private MyTextview myTextview = null;
private String str = "曾經有一份真誠的愛情放在我面前,我沒有珍惜,等我失去的時候我才後悔莫及,人世間最痛苦的事莫過於此。 \n" +
"如果上天能夠給我一個再來一次的機會,我會對那個女孩子說三個字:我愛你。 \n" +
"如果非要在這份愛上加上一個期限,我希望是…… \n" +
"一萬年";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTextview = (MyTextview) findViewById(R.id.tv);
myTextview.setText(str);
}
}
這樣就搞定了。
然後我給出自定義控件的所有代碼
public class MyTextview extends LinearLayout {
private TextView textView = null;
private ImageView img = null;
//字體顏色
protected int textColor;
//字體大小
protected float textSize;
//最大行數
protected int maxLine;
//文字
protected String text;
//默認顏色
public int defaultTextColor = Color.BLACK;
//默認字體大小
public int defaultTextSize = 14;
//默認行數
public int defaultLine = 2;
public MyTextview(Context context) {
super(context);
initView();
}
public MyTextview(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
initAttrs(context, attrs);
textListener();
}
public MyTextview(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
initAttrs(context, attrs);
textListener();
}
public void initAttrs(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyTextStyle);
textColor = typedArray.getColor(R.styleable.MyTextStyle_textColor, defaultTextColor);
textSize = typedArray.getDimensionPixelSize(R.styleable.MyTextStyle_textSize, defaultTextSize);
maxLine = typedArray.getInt(R.styleable.MyTextStyle_maxLine, defaultLine);
text = typedArray.getString(R.styleable.MyTextStyle_text);
setMyView(textColor, textSize, maxLine, text);
//用完 回收一下
typedArray.recycle();
}
public void initView() {
setOrientation(VERTICAL);
setGravity(Gravity.RIGHT);
int padding = dip2px(getContext(), 10);
textView = new TextView(getContext());
//行間距
textView.setLineSpacing(3f, 1f);
addView(textView, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
img = new ImageView(getContext());
img.setPadding(padding, padding, padding, padding);
//imageview設置圖片
img.setImageResource(R.mipmap.textimg);
LayoutParams llp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
addView(img, llp);
}
protected void setMyView(int color, float size, final int line, String text) {
//文本設置顏色
textView.setTextColor(color);
//字體大小
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, size);
//設置文字
textView.setText(text);
//設置TextView的高度
textView.setHeight(textView.getLineHeight() * line);
//線程更新UI
post(new Runnable() {
@Override
public void run() {
if (textView.getLineCount() > line) {
img.setVisibility(VISIBLE);
} else {
img.setVisibility(GONE);
}
}
});
}
protected void textListener() {
setOnClickListener(new OnClickListener() {
boolean isGo;
@Override
public void onClick(View v) {
isGo = !isGo;
textView.clearAnimation();
//相差的高度
final int deltaValue;
//初始的高度
final int startValue = textView.getHeight();
//動畫播放的時間
int duration = 1000;
if (isGo) {
//Image圖片打開的動畫
deltaValue = textView.getLineHeight() * textView.getLineCount() - startValue;
RotateAnimation animation = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animation.setDuration(duration);
animation.setFillAfter(true);
img.startAnimation(animation);
} else {
//Image圖片關閉的動畫
deltaValue = textView.getLineHeight() * maxLine - startValue;
RotateAnimation animation = new RotateAnimation(180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animation.setDuration(duration);
animation.setFillAfter(true);
img.startAnimation(animation);
}
//打開或者關閉的時候textview下面的展開動畫
Animation animation = new Animation() {
protected void applyTransformation(float interpolatedTime, Transformation t) {
textView.setHeight((int) (startValue + deltaValue * interpolatedTime));
}
};
animation.setInterpolator(new BounceInterpolator());
animation.setDuration(duration);
textView.startAnimation(animation);
}
});
}
public TextView getTextView() {
return textView;
}
public void setText(CharSequence charSequence) {
textView.setText(charSequence);
}
public static int dip2px(Context context, float dipValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
}