寫在前面的話: 在正常項目流程中,我們很多情況下會碰到點(diǎn)擊顯示更多文本,這樣可以利于頁面變化加載,點(diǎn)擊顯示更多可能會非常常用,現(xiàn)在博主利用自己的閑暇時間來一點(diǎn)一點(diǎn)完成一個自定義控件,這個控件可以滿足大多數(shù)情況的需求。
思路:
在寫程序的時候,最需要的是思路,好的思路是成功的一半,我們來看看我們的最基本的需求效果:
1、需要在文字特別多的情況下顯示只有確定的行數(shù)
2、點(diǎn)擊右側(cè)圖片將所有的文字顯示出來
3、文字在左側(cè)覆蓋大部分布局,圖標(biāo)在右側(cè)點(diǎn)擊顯示更多
4、顯示的文本不會因為重用優(yōu)化視圖從而發(fā)生狀態(tài)錯位
實(shí)現(xiàn)需求:
1、繼承LinearLayout:
public class ExpandableContainer extends LinearLayout { //繼承線性布局的好處是可以由系統(tǒng)將我們的兩個view進(jìn)行線性分配,可控制的圖形大小以及可變化的view的填充情況 }
2、根據(jù)Textview的即textview.setEllipsize()與textview.setMaxLines兩個方法重繪View達(dá)到顯示更多的效果:
/**
*進(jìn)行重繪view
*/
private void onresfreshView() {
if (isExpanded) {
textView.setEllipsize(null);
textView.setMaxLines(Integer.MAX_VALUE);
initView();
} else {
textView.setEllipsize(TextUtils.TruncateAt.END);
textView.setMaxLines(lines);
initView();
}
}
3、在多條目布局的情況下顯示狀態(tài)會讓該布局的顯示狀態(tài)發(fā)生顯示亂位,于是用自帶內(nèi)存的方式來解決這一問題
/**
*在listview , gridview, recyclerview的條目中使用此方法,防止重繪布局
* @param text 你所要填充的文本
* @param position 當(dāng)前控件所在的position
*/
public synchronized void setText(String text, int position) {
this.position = position;
this.text = text;
initView();
if (null!=map&&map.size()>0&&map.keySet().contains(position)){
isExpanded = map.get(position);
}else isExpanded=false;
map.put(position,isExpanded);
onresfreshView();
}
4、使用軟引用來做防止內(nèi)存泄漏,在view移除的時候做clear清理對象,重寫view的最終銷毀方法onDetachedFromWindow在里面進(jìn)行清理靜態(tài)對象防止內(nèi)存泄漏
/**
* 用軟引用避免內(nèi)存泄露
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mapSoftReference.clear();
}
5、以上就是所有的view的最重要的幾個方法,根據(jù)這些方法的自定義的使用,能夠很好的完成我們的預(yù)期效果:
項目核心view的代碼:
/**
* Created by ke_li on 2017/1/13.
* 自定義顯示更多文本
*/
public class ExpandableContainer extends LinearLayout {
//默認(rèn)的點(diǎn)擊圖標(biāo)
private static final int IMAGE_RES = R.mipmap.explain;
// 默認(rèn)圖標(biāo)的高度
private static final int IMAGE_HEIGHT = 0;
// 默認(rèn)圖標(biāo)的寬度
private static final int IMAGE_WIDTH = 0;
// 默認(rèn)顯示文本的行數(shù)
private static final int EXPAND_LINE = 2;
// 控制默認(rèn)顯示文本的行數(shù)
private int lines;
// 判斷是否展開
private boolean isExpanded;
// 變化的TextView
private TextView textView;
// 點(diǎn)擊擴(kuò)展的圖標(biāo)
private ImageView imageView;
// 顯示文本
private String text ;
// 控制多少position
private int position;
/**
* 將狀態(tài)記錄給緩存,下次取的時候進(jìn)行修改
*/
private static Map<Integer,Boolean> map = new HashMap<>();
// 建立緩存機(jī)制
SoftReference<Map> mapSoftReference = new SoftReference<Map>(map);
public ExpandableContainer(Context context) {
this(context, null);
}
private void init(Context context, AttributeSet attrs) {
//創(chuàng)建TextView
textView = new TextView(context);
//創(chuàng)建ImageView 負(fù)責(zé)點(diǎn)擊imageview來展示更多
imageView = new ImageView(context);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ExpandableContainer);
String value = array.getString(R.styleable.ExpandableContainer_setText);
int resourse = array.getInteger(R.styleable.ExpandableContainer_setImageResource, IMAGE_RES);
int width = array.getDimensionPixelOffset(R.styleable.ExpandableContainer_image_width, IMAGE_WIDTH);
int height = array.getDimensionPixelOffset(R.styleable.ExpandableContainer_image_height, IMAGE_HEIGHT);
lines = array.getInteger(R.styleable.ExpandableContainer_expandableLine, EXPAND_LINE);
final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(context, attrs);
layoutParams.gravity = Gravity.BOTTOM;
LinearLayout.LayoutParams imageParams = new LinearLayout.LayoutParams(width, height);
LinearLayout.LayoutParams TextParams = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1);
textView.setText(value);
textView.setLayoutParams(TextParams);
imageView.setImageResource(resourse);
imageView.setLayoutParams(imageParams);
textView.setMaxLines(lines);
textView.setEllipsize(TextUtils.TruncateAt.END);
this.setLayoutParams(layoutParams);
imageView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (!isExpanded) {
textView.setEllipsize(null);
isExpanded = true;
textView.setMaxLines(Integer.MAX_VALUE);
initView();
} else {
textView.setEllipsize(TextUtils.TruncateAt.END);
isExpanded = false;
textView.setMaxLines(lines);
initView();
}
map.put(position,isExpanded);
}
});
}
/**
* 普通填充控件
* @param text
*/
public void setText(String text) {
this.text = text;
initView();
}
/**
* 進(jìn)行重繪view
*/
private void onresfreshView() {
if (isExpanded) {
textView.setEllipsize(null);
textView.setMaxLines(Integer.MAX_VALUE);
initView();
} else {
textView.setEllipsize(TextUtils.TruncateAt.END);
textView.setMaxLines(lines);
initView();
}
}
@Override
public void requestLayout() {
super.requestLayout();
}
private void initView() {
textView.setText(text);
this.removeAllViews();
this.addView(textView);
this.addView(imageView);
}
public ExpandableContainer(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public ExpandableContainer(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
/**
* 在listview , gridview, recyclerview的條目中使用此方法,防止重繪布局
*
* @param text 你所要填充的文本
* @param position 當(dāng)前控件所在的position
*/
public synchronized void setText(String text, int position) {
this.position = position;
this.text = text;
initView();
if (null!=map&&map.size()>0&&map.keySet().contains(position)){
isExpanded = map.get(position);
}else isExpanded=false;
map.put(position,isExpanded);
onresfreshView();
}
/**
* 用軟引用避免內(nèi)存泄露
*/
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mapSoftReference.clear();
}}