Android自定义ViewGroup之子控件的自动换行和添加删除
2016-01-06 17:13
666 查看
常用的布局类型并不能满足所有需求,这时就会用到ViewGroup。
ViewGroup作为一个放置View的容器,并且我们在写布局xml的时候,会告诉容器(凡是以layout为开头的属性,都是为用于告诉容器的),我们的宽度(layout_width)、高度(layout_height)、对齐方式(layout_gravity)等;当然还有margin等;于是乎,ViewGroup需要做的事情是:给childView计算出建议的宽和高和测量模式 ;决定childView的位置;为什么只是建议的宽和高,而不是直接确定呢,别忘了childView宽和高可以设置为wrap_content,这样只有childView才能计算出自己的宽和高。
代码注释很详细,直接看代码即可,没贴源码,因为这是从一个项目里面抠出来的。
先写一个自定义LinearLayout,它的功能是自适应子控件:
主活动完成的功能就是上面贴图演示的功能,让两个自定义ViewGroup能够添加删除子控件,子控件是在代码中动态搭建的,下面会给出方法:
活动:
布局:
drawable下的文件:
item_bg.xml:
item_select_bg.xml:
item_select_bg_below.xml:
最后感谢原创者的无私奉献精神。
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>
最后感谢原创者的无私奉献精神。
相关文章推荐
- 利用HTML5开发Android
- 【Android】BaseAdapter示例
- 结合源码分析android的消息机制
- android调用摄像头拍照并显示
- 关于清除Android Studio中清除代理设置
- Android Intent传递数据
- 我的360
- Android获取其他进程加载的模块基地址
- 使用 Xcode 和 Android Studio 管理 iOS 和 Android 项目版本
- 细说Android事件传递机制(dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent)
- Android studio 启动的时候遇到tool.jar 没有找到的问题z
- Android ContentProvider UnderStanding
- Android的Activity屏幕切换动画-左右滑动切换
- android可拖动的购物车效果(含点击放入购物车动画代码)
- android 源码链接
- android studio下载的好地址
- StringUtil
- MPAndroidChart
- Android入门学习
- 如何使用Retrofit写一个Android的REST客户端的小教程