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


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


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

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

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);
        }
    }
 
}

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

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);
        }
    }
}

布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:background="@drawable/item_bg">
        <LinearLayout
            android:id="@+id/linearlayout_back"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="5dp"
            android:gravity="center"
            android:orientation="horizontal">
            <ImageButton
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@drawable/btn_back"/>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="报表"
                android:textSize="@dimen/head_left_text_size"/>
        </LinearLayout>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="订阅"
            android:textSize="@dimen/head_center_text_size"/>

    </RelativeLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/item_bg"
        android:orientation="horizontal"
        android:paddingBottom="12dp"
        android:paddingLeft="8dp"
        android:paddingTop="12dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="已添加"
            android:textSize="16dp"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="(点击删除)"
            android:textSize="13dp"/>
    </LinearLayout>

    <com.test.shiweiwei.myproject.selfish_view.self_defined_view_group.ItemContainer
        android:id="@+id/item_container_add"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/item_bg">

    </com.test.shiweiwei.myproject.selfish_view.self_defined_view_group.ItemContainer>

    <LinearLayout
        android:id="@+id/linearlayout_attention_null"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:paddingTop="35dp"
        android:paddingBottom="35dp"
        android:gravity="center"
        android:background="@drawable/item_bg"
        android:visibility="gone">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/attendance_null"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="13dp"
            android:text="无报表信息"/>
    </LinearLayout>

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <LinearLayout
        android:id="@+id/linearlayout_remove"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/item_bg"
            android:orientation="horizontal"
            android:layout_marginTop="@dimen/first_page_item_margin_top"
            android:paddingBottom="12dp"
            android:paddingLeft="8dp"
            android:paddingTop="12dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="可添加"
                android:textSize="16dp"/>

        </LinearLayout>

        <com.test.shiweiwei.myproject.selfish_view.self_defined_view_group.ItemContainer
            android:id="@+id/item_container_remove"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/item_bg">

        </com.test.shiweiwei.myproject.selfish_view.self_defined_view_group.ItemContainer>
    </LinearLayout>

</LinearLayout>


drawable下的文件:
item_bg.xml:

<!--?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>

item_select_bg.xml:

<!--?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>

item_select_bg_below.xml:

<!--?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>

最后感谢原创者的无私奉献精神。



Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐