Android自定义ViewGroup之子控件的自动换行和添加删除

概述:

常用的布局类型并不能满足所有需求,这时就会用到ViewGroup。

ViewGroup作为一个放置View的容器,并且我们在写布局xml的时候,会告诉容器(凡是以layout为开头的属性,都是为用于告诉容器的),我们的宽度(layout_width)、高度(layout_height)、对齐方式(layout_gravity)等;当然还有margin等;于是乎,ViewGroup需要做的事情是:给childView计算出建议的宽和高和测量模式 ;决定childView的位置;为什么只是建议的宽和高,而不是直接确定呢,别忘了childView宽和高可以设置为wrap_content,这样只有childView才能计算出自己的宽和高。

博客名已经说明了这篇博客要将给出的内容,不用赘述。

先看效果图:
这里写图片描述

代码注释很详细,直接看代码即可,没贴源码,因为这是从一个项目里面抠出来的。

Demo

先写一个自定义LinearLayout,它的功能是自适应子控件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<code class = "language-java" hljs= "" > public class ItemContainer extends LinearLayout {
     private int width; //组件宽
     private int height; //组件高
     private int childCount;
     private int childMarginLeft = SizeConvert.dip2px(getContext(), 8 ); //子控件相对左边控件的距离
     private int childMarginHorizonTal = SizeConvert.dip2px(getContext(), 10 ); //子控件相对最左、最右的距离
     private int childMarginTop = SizeConvert.dip2px(getContext(), 8 ); //子控件相对顶部控件的距离
     private int childWidth; //子控件宽
     private int childHeight; //子控件高
 
     public ItemContainer(Context context) {
         super (context);
     }
 
     public ItemContainer(Context context, AttributeSet attrs) {
         super (context, attrs);
     }
 
     @Override
     protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec) {
         super .onMeasure(widthMeasureSpec, heightMeasureSpec);
         childCount = getChildCount(); //得到子控件数量
         if (childCount> 0 ) {
             childWidth = (width - childMarginLeft * 4 ) / 3 ;
             childHeight = SizeConvert.dip2px(getContext(), 42 ); //给子控件的高度一个定值
             //根据子控件的高和子控件数目得到自身的高
             height = childHeight * ((childCount- 1 )/ 3 + 1 ) + childMarginHorizonTal * 2 + childMarginTop*((childCount- 1 )/ 3 );
             Log.d(childHeight,childHeight+);
         } else {
             //如果木有子控件,自身高度为0,即不显示
             height = 0 ;
         }
         width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
         Log.d(height,height+);
         //根据自身的宽度约束子控件宽度
         measureChildren(widthMeasureSpec, heightMeasureSpec);
         //设置自身宽度
         setMeasuredDimension(width, height);
     }
 
     @Override
     protected void onLayout( boolean changed, int l, int t, int r, int b) {
         /**
          * 遍历所有子控件,并设置它们的位置和大小
          * 每行只能有三个子控件,且高度固定,宽度相同,且每行正好布满
          */
         for ( int i = 0 ; i < childCount; i++) {
             View childView = getChildAt(i); //得到当前子控件
             childView.layout((i% 3 ) * childWidth + (i% 3 + 1 )*childMarginLeft
                     , (i / 3 )*childHeight + childMarginHorizonTal + (i / 3 )*childMarginTop
                     , (i% 3 + 1 ) * childWidth + (i% 3 + 1 )*childMarginLeft
                     , (i / 3 + 1 )*childHeight + childMarginHorizonTal + (i / 3 )*childMarginTop);
         }
     }
 
}</code>

主活动完成的功能就是上面贴图演示的功能,让两个自定义ViewGroup能够添加删除子控件,子控件是在代码中动态搭建的,下面会给出方法:
活动:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<code class = "language-java" hljs= "" > public class ItemOperateActivity extends BaseActivity {
     private LinearLayout mContentNoItem;
     private LinearLayout mContentItemRemove;
     private ItemContainer mItemContainerAdd;
     private ItemContainer mItemContainerRemove;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.activity_item_operate);
         mContentNoItem = (LinearLayout) findViewById(R.id.linearlayout_attention_null);
         mContentItemRemove = (LinearLayout) findViewById(R.id.linearlayout_remove);
         mItemContainerAdd = (ItemContainer) findViewById(R.id.item_container_add);
         mItemContainerRemove = (ItemContainer) findViewById(R.id.item_container_remove);
 
         initItems( new String[]{随时定位, 客户拜访}, new String[]{新增客户, 客户总量});
 
     }
 
     /**
      * 添加条目时需要调用的方法
      * @param name
      */
     private void addItem(String name) {
         mContentNoItem.setVisibility(View.GONE);
         Button button = new Button(getApplicationContext());
         ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT
                 , 0 );
         button.setLayoutParams(params);
         button.setText(name);
         button.setGravity(Gravity.CENTER);
         button.setBackgroundResource(R.drawable.item_select_bg);
         button.setTextSize( 13 );
         button.setTextColor(Color.argb( 255 , 47 , 79 , 79 )); //铅灰色
         button.setOnClickListener( new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 mItemContainerAdd.removeView(v);
                 removeItem(((Button) v).getText().toString());
                 if (mItemContainerAdd.getChildCount()== 0 ) {
                     mContentNoItem.setVisibility(View.VISIBLE);
                 }
             }
 
         });
         mItemContainerAdd.addView(button);
 
     }
 
     /**
      * 删除条目时需要调用的方法
      * @param name
      */
     private void removeItem(String name) {
         mContentItemRemove.setVisibility(View.VISIBLE);
         Button button = new Button(getApplicationContext());
         ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT
                 , 0 );
         button.setLayoutParams(params);
         button.setText(name);
         button.setGravity(Gravity.CENTER);
         button.setBackgroundResource(R.drawable.item_select_bg_below);
         button.setTextSize( 13 );
         button.setTextColor(Color.argb( 255 , 47 , 79 , 79 )); //铅灰色
         button.setOnClickListener( new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 /**
                  * 点击按钮时,删除
                  */
                 mItemContainerRemove.removeView(v);
                 addItem(((Button) v).getText().toString());
 
                 if (mItemContainerRemove.getChildCount() == 0 ) {
                     mContentItemRemove.setVisibility(View.GONE);
                 }
             }
         });
         mItemContainerRemove.addView(button);
     }
 
     /**
      * 初始化子控件
      * @param itemsAdd 已添加的子控件名数组
      * @param itemsRemove 可添加的子控件名数组
      */
     private void initItems(String[] itemsAdd, String[] itemsRemove) {
         for (String itemAdd : itemsAdd) {
             addItem(itemAdd);
         }
         for (String itemRemove : itemsRemove) {
             removeItem(itemRemove);
         }
     }
}</code>

布局:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<code class = "language-xml" hljs= "" ><!--?xml version= 1.0 encoding=utf- 8 ?-->
<linearlayout android:layout_height= "match_parent" android:layout_width= "match_parent" android:orientation= "vertical" xmlns:android= "http://schemas.android.com/apk/res/android" >
 
     <relativelayout android:background= "@drawable/item_bg" android:layout_height= "60dp" android:layout_width= "match_parent" >
         <linearlayout android:gravity= "center" android:id= "@+id/linearlayout_back" android:layout_alignparentleft= "true" android:layout_centervertical= "true" android:layout_height= "wrap_content" android:layout_marginleft= "5dp" android:layout_width= "wrap_content" android:orientation= "horizontal" >
             <imagebutton android:background= "@drawable/btn_back/" android:layout_height= "wrap_content" android:layout_width= "wrap_content" >
 
             <textview android:layout_height= "wrap_content" android:layout_width= "wrap_content" android:text= "报表" android:textsize= "@dimen/head_left_text_size/" >
         </textview></imagebutton></linearlayout>
 
         <textview android:layout_centerinparent= "true" android:layout_height= "wrap_content" android:layout_width= "wrap_content" android:text= "订阅" android:textsize= "@dimen/head_center_text_size/" >
 
     </textview></relativelayout>
 
     <linearlayout android:background= "@drawable/item_bg" android:layout_height= "wrap_content" android:layout_width= "match_parent" android:orientation= "horizontal" android:paddingbottom= "12dp" android:paddingleft= "8dp" android:paddingtop= "12dp" >
 
         <textview android:layout_height= "wrap_content" android:layout_width= "wrap_content" android:text= "已添加" android:textsize= "16dp/" >
 
         <textview android:layout_height= "wrap_content" android:layout_width= "wrap_content" android:text= "(点击删除)" android:textsize= "13dp/" >
     </textview></textview></linearlayout>
 
     <com.test.shiweiwei.myproject.selfish_view.self_defined_view_group.itemcontainer android:background= "@drawable/item_bg" android:id= "@+id/item_container_add" android:layout_height= "wrap_content" android:layout_width= "match_parent" >
 
     </com.test.shiweiwei.myproject.selfish_view.self_defined_view_group.itemcontainer>
 
     <linearlayout android:background= "@drawable/item_bg" android:gravity= "center" android:id= "@+id/linearlayout_attention_null" android:layout_height= "wrap_content" android:layout_width= "match_parent" android:orientation= "vertical" android:paddingbottom= "35dp" android:paddingtop= "35dp" android:visibility= "gone" >
         <imageview android:layout_height= "wrap_content" android:layout_width= "wrap_content" android:src= "@mipmap/attendance_null/" >
         <textview android:layout_height= "wrap_content" android:layout_width= "wrap_content" android:text= "无报表信息/" android:textsize= "13dp" >
     </textview></imageview></linearlayout>
 
     <imageview android:layout_height= "wrap_content/" android:layout_width= "match_parent" >
 
     <linearlayout android:id= "@+id/linearlayout_remove" android:layout_height= "wrap_content" android:layout_width= "match_parent" android:orientation= "vertical" >
         <linearlayout android:background= "@drawable/item_bg" android:layout_height= "wrap_content" android:layout_margintop= "@dimen/first_page_item_margin_top" android:layout_width= "match_parent" android:orientation= "horizontal" android:paddingbottom= "12dp" android:paddingleft= "8dp" android:paddingtop= "12dp" >
 
             <textview android:layout_height= "wrap_content" android:layout_width= "wrap_content" android:text= "可添加" android:textsize= "16dp/" >
 
         </textview></linearlayout>
 
         <com.test.shiweiwei.myproject.selfish_view.self_defined_view_group.itemcontainer android:background= "@drawable/item_bg" android:id= "@+id/item_container_remove" android:layout_height= "wrap_content" android:layout_width= "match_parent" >
 
         </com.test.shiweiwei.myproject.selfish_view.self_defined_view_group.itemcontainer>
     </linearlayout>
 
</imageview></linearlayout></code>

drawable下的文件:
item_bg:

?
1
2
3
4
5
<code class = "language-xml" hljs= "" ><!--?xml version= 1.0 encoding=utf- 8 ?-->
<shape xmlns:android= "http://schemas.android.com/apk/res/android" >
     <solid android:color= "@color/white" ></solid>
     <stroke android:color= "@color/stroke_vertical" android:width= "0.3dp" ></stroke>
</shape></code>

item_select_bg:

?
1
2
3
4
5
6
7
<code class = "language-xml" hljs= "" ><!--?xml version= 1.0 encoding=utf- 8 ?-->
<shape xmlns:android= "http://schemas.android.com/apk/res/android" >
     <solid android:color= "@color/white" ></solid>
     <stroke android:color= "@color/dark_brow" android:width= "0.3dp" ></stroke>
     <corners android:radius= "4dp" ></corners>
     <padding android:bottom= "12dp" android:top= "12dp" ></padding>
</shape><!--?xml version= 1.0 encoding=utf- 8 ?--></code>

item_select_bg_below:

?
1
2
3
4
5
6
<code class = "language-xml" hljs= "" ><!--?xml version= 1.0 encoding=utf- 8 ?-->
<shape xmlns:android= "http://schemas.android.com/apk/res/android" >
     <solid android:color= "@color/white" ></solid>
     <stroke android:color= "@color/stroke_vertical" android:width= "0.3dp" ></stroke>
     <corners android:radius= "4dp" ></corners>
  </shape></code>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值