Android--根据子控件的大小自动换行的ViewGroup

1、自定义ViewGroup

  1 /**
  2  * Created by Administrator on 2016/2/26.
  3  *
  4  * --------自动换行的ViewGroup-----------
  5  */
  6 public class LineWrapLayout extends ViewGroup {
  7     private static final boolean DEBUG = true;
  8     private static final String TAG = "AutoLineFeedLayout";
  9
 10     /**
 11      * 左间距
 12      */
 13     private int paddingLeft = 10;
 14     /**
 15      * 右间距
 16      */
 17     private int paddingRight = 10;
 18     /**
 19      *
 20      */
 21     private int paddingTop = 10;
 22     /**
 23      *
 24      */
 25     private int paddingBottom = 10;
 26
 27     /**
 28      * 水平方向间距
 29      */
 30     private int horizontalSpace = 10;
 31     /**
 32      * 行间距
 33      */
 34     private int verticalSpace = 5;
 35
 36
 37     private List<Integer> listX;
 38     private List<Integer> listY;
 39
 40     public LineWrapLayout(Context context) {
 41         super(context);
 42
 43     }
 44     public LineWrapLayout(Context context, AttributeSet attrs) {
 45         super(context, attrs);
 46         init(attrs);
 47     }
 48
 49     public LineWrapLayout(Context context, AttributeSet attrs, int defStyle) {
 50         super(context, attrs, defStyle);
 51         init(attrs);
 52     }
 53
 54
 55     @Override
 56     protected void onLayout(boolean changed, int l, int t, int r, int b) {
 57         if(DEBUG) Log.d(TAG, "--- onLayout changed :" + changed + " l :" + l + ",t :" + t + ",r :" + r + ",b :" + b);
 58         int count = getChildCount();
 59         int width = getWidth();
 60         Log.i(TAG, "宽度 :"+width);
 61
 62
 63         int startOffsetX = paddingLeft;// 横坐标开始
 64         int startOffsety = 0;//纵坐标开始
 65         int rowCount = 1;
 66
 67         int preEndOffsetX = startOffsetX;
 68
 69         for (int i = 0; i < count; i++) {
 70             final View childView = getChildAt(i);
 71
 72             int w = childView.getMeasuredWidth();
 73             int h = childView.getMeasuredHeight();
 74
 75             int x = listX.get(i);
 76             int y = listY.get(i);
 77
 78             // 布局子控件
 79             childView.layout(x, y, x + w, y + h);
 80         }
 81     }
 82     @Override
 83     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 84         if(DEBUG) Log.v(TAG, "--- onMeasure()");
 85
 86         int count = getChildCount();
 87         int width = measureWidth(widthMeasureSpec);
 88         Log.i(TAG, "宽度 :"+width);
 89
 90
 91         int startOffsetX = paddingLeft;// 横坐标开始
 92         int startOffsety = 0+paddingTop;//纵坐标开始
 93         int rowCount = 1;
 94
 95         int preEndOffsetX = startOffsetX;
 96
 97         listX.clear();
 98         listY.clear();
 99         for (int i = 0; i < count; i++) {
100             Log.v(TAG, "----");
101             final View childView = getChildAt(i);
102             // 设置子空间Child的宽高
103             childView.measure(0,0);
104             /* 获取子控件Child的宽高 */
105             int childWidth = childView.getMeasuredWidth();
106             int childHeight = childView.getMeasuredHeight();
107             Log.v(TAG, "childWidth :"+childWidth+" childHeight :"+childHeight);
108             preEndOffsetX = startOffsetX + childWidth /*+ CHILD_MARGIN*/;
109             //TODO [yaojian]margin属性?
110             if (preEndOffsetX > width - paddingRight ) {
111                 if (startOffsetX > paddingLeft) {
112                     /* 换行  */
113                     startOffsetX = paddingLeft;
114                     startOffsety += childHeight+verticalSpace;
115                     rowCount++;
116                 }
117             }
118             Log.d(TAG, "measure child :"+startOffsetX+", "+startOffsety+", "+preEndOffsetX+", "+(startOffsety+childHeight));
119             listX.add(startOffsetX);
120             listY.add(startOffsety);
121
122 //            childView.layout(startOffsetX, startOffsety, preEndOffsetX, startOffsety+childHeight);
123             startOffsetX = startOffsetX + childWidth + horizontalSpace;
124         }
125         int lastLineHeight = 0;
126         View lastChild = getChildAt(count-1);
127         if(null != lastChild){
128             lastLineHeight = lastChild.getMeasuredHeight();
129         }
130         setMeasuredDimension(measureWidth(widthMeasureSpec), startOffsety+lastLineHeight+paddingBottom);
131 //        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
132
133         // 注意setMeasuredDimension和resolveSize的用法
134 //        setMeasuredDimension(resolveSize(measuredWidth, widthMeasureSpec),
135 //                resolveSize(top, heightMeasureSpec));
136     }
137
138     private int measureWidth(int measureSpec) {
139         int specMode = MeasureSpec.getMode(measureSpec);
140         int specSize = MeasureSpec.getSize(measureSpec);
141
142
143         // Default size if no limits are specified.
144         int result = 400;
145
146         if (specMode == MeasureSpec.AT_MOST) {
147             // Calculate the ideal size of your control
148             // within this maximum size.
149             // If your control fills the available space
150             // return the outer bound.
151             result = specSize;
152         } else if (specMode == MeasureSpec.EXACTLY) {
153             // If your control can fit within these bounds return that value.
154             result = specSize;
155         }
156         return result;
157     }
158
159     private void init(AttributeSet attrs) {
160         TypedArray attrArray = getContext().obtainStyledAttributes(attrs, R.styleable.AutoLineFeedLayout);
161         int attrCount = attrArray.getIndexCount();
162         for (int i = 0; i < attrCount; i++) {
163             int attrId = attrArray.getIndex(i);
164             switch (attrId) {
165                 case R.styleable.AutoLineFeedLayout_horizontalSpacing:{
166                     float dimen = attrArray.getDimension(attrId, 0);
167                     horizontalSpace = (int) dimen;
168                 }
169                 break;
170                 case R.styleable.AutoLineFeedLayout_verticalSpacing:{
171                     float dimen = attrArray.getDimension(attrId, 0);
172                     verticalSpace = (int) dimen;
173                 }
174                 break;
175                 case R.styleable.AutoLineFeedLayout_paddingBottom:{
176                     float dimen = attrArray.getDimension(attrId, 0);
177                     paddingBottom = (int) dimen;
178                 }
179                 break;
180                 case R.styleable.AutoLineFeedLayout_paddingLeft:{
181                     float dimen = attrArray.getDimension(attrId, 0);
182                     paddingLeft = (int) dimen;
183                 }
184                 break;
185                 case R.styleable.AutoLineFeedLayout_paddingRight:{
186                     float dimen = attrArray.getDimension(attrId, 0);
187                     paddingRight = (int) dimen;
188                 }
189                 break;
190                 case R.styleable.AutoLineFeedLayout_paddingTop:{
191                     float dimen = attrArray.getDimension(attrId, 0);
192                     paddingTop = (int) dimen;
193                 }
194                 break;
195                 case R.styleable.AutoLineFeedLayout_debug:{
196
197                 }
198                 break;
199
200                 default:
201                     break;
202             }
203
204         }
205
206         listX = new ArrayList<Integer>();
207         listY = new ArrayList<Integer>();
208     }
209 }

2、有一部分自定义属性可供使用 attrs.xml

    <declare-styleable name="AutoLineFeedLayout">
        <attr name="debug" format="boolean"></attr>

        <attr name="paddingLeft" format="reference|dimension"/>
        <attr name="paddingRight" format="reference|dimension"/>
        <attr name="paddingTop" format="reference|dimension"/>
        <attr name="paddingBottom" format="reference|dimension"/>

        <attr name="verticalSpacing" format="reference|dimension"/>
        <attr name="horizontalSpacing" format="reference|dimension"/>
    </declare-styleable>

3、在布局文件中和普通ViewGroup使用相同

4、在Activity中动态添加View或者ViewGroup

for (int i = 0;i < myData.getList().length;i++){
                        View child = View.inflate(ZhuanTiActivity.this,R.layout.item_mygridview_layout,null);
                        TextView textView = (TextView) child.findViewById(R.id.tv_title_item);
                        textView.setText(myData.getList()[i].getName());
                        textView.setTextColor(Color.argb(255, colorR, colorG, colorB));
                        textView.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                Log.d("aaa",textView.getText());
                            }
                        });
                        custom_index_zhuanTiActivity.addView(child);
                    }
时间: 2024-08-09 06:32:29

Android--根据子控件的大小自动换行的ViewGroup的相关文章

[转]Android ListView最佳处理方式,ListView拖动防重复数据显示,单击响应子控件

Android ListView最佳处理方式,ListView拖动防重复数据显示,单击响应子控件. 1.为了防止拖动ListView时,在列表末尾重复数据显示.需要加入 HashMap<Integer,View> lmap = new HashMap<Integer,View>();其中Integer为列表位置,View为子项视图,加入数据前首先if (lmap.get(position)==null) ,满足条件时,加入lmap.put(position, convertView

Android嵌套滑动控件的冲突解决和ViewPager适配当前子控件高度不留空白的办法

最近项目有一个需求,需要多层可滑动控件的嵌套展示,demo效果如下,demo的下载地址在最后 咋一看好像挺简单啊,不就是一个ScrollView + ViewPager + ListView吗,我开始也这样觉得,也用的这种方式实现,结果始终和效果不对劲.这里总结几点问题: 两个或两个以上的滑动控件嵌套时,如果layout_height采用的是wrap_content会造成内部滑动控件的高度不能正确的计算,会导致内部滑动控件的高度始终为0,除非你用定值设置,比如300dp. 两个相同滑动方向的滑动

Android 布局之LinearLayout 子控件weight权重的作用详析(转)

关于Android开发中的LinearLayout子控件权重android:layout_weigh参数的作用,网上关于其用法有两种截然相反说法: 说法一:值越大,重要性越高,所占用的空间越大: 说法二:值越大,重要性越低,所占用的空间越小. 到底哪个正确?哪个错误?抑或还有其他解释?请点击查看关于weight 权重参数作用的详分析: 其实这两种情况都不太准确: 准确的解释是,weight 权限 是用于分配父控件某一方向上尺寸-所有子控件在该方向上设定尺寸和 所得值的一个参数,把这个相减得到的结

如果希望点击父控件子控件也响应的话, 可以给子控件加如下属性: ?android:duplicateParentState="true"

如果希望点击父控件子控件也响应的话, 可以给子控件加如下属性: android:duplicateParentState="true" 来自为知笔记(Wiz)

Android 布局之LinearLayout 子控件weight权重的作用详析

关于Android开发中的LinearLayout子控件权重android:layout_weigh参数的作用,网上关于其用法有两种截然相反说法: 说法一:值越大,重要性越高,所占用的空间越大: 说法二:值越大,重要性越低,所占用的空间越小. 到底哪个正确?哪个错误?抑或还有其他解释?请点击查看关于weight 权重参数作用的详分析: 其实这两种情况都不太准确: 准确的解释是,weight 权限 是用于分配父控件某一方向上尺寸-所有子控件在该方向上设定尺寸和 所得值的一个参数,把这个相减得到的结

Android学习分享:执行某ViewGroup的动画时,子控件太多导致动画执行卡顿的问题

最近在项目中遇到一个问题,我有一个LinearLayout,里面装载了许多ImageView控件,ImageView控件显示着自己的图片,这个LinearLayout支持双指缩放,缩放采用ScaleAnimation来实现,但是但是在缩放过程中,屏幕十分卡顿,缩放效果根本没有跟上手指的缩放动作.后来在Google上查了一番,查到一个API,叫setAnimationDrawCacheEnabled(boolean enabled): /** * Enables or disables the c

子控件根据父控件行宽自动换行---LineWrapLayout实现

一些带搜索功能的app,在搜索栏下面一般会提供一些关键字供用户选择. 也可以根据用户输入的文字,在下一次使用的时候该文字出现在常用关键字里面,只要轻轻一点就可以搜索了,无需再次输入. 关键字可以动态添加,这就要考虑换行的问题了 废话不多说,先上效果图: 先定义2个自定义属性 <declare-styleable name="linewarplayout"> <attr name="magin" format="integer"

Android自定义组合控件内子控件无法显示问题

今天自定义了一个组合控件,与到了个奇葩问题: 我自定义了一个RelativeLayout,这个layout内有多个子控件.但奇怪的是这些子控件一直显示不出来.调试了一下午,竟然是因为在获取(inflate)布局时没有添加到Root.

记录下帮助一位网友解决的关于android子控件的onTouch或onClick和父OnTouch 冲突的问题。

前三天收到位网友的私信求助,问题大概如标题所示.具体是下面的情况,个人感觉,这个问题挺有趣,也会在实际项目开发中很常见.不想看前奏的请直接跳至解决方法. 问题原型: 父控件是自定义的 LinearLayout,目的是实现下拉刷新,这个自定义View的实现下拉操作思想是通过检测 onTouch 事件,然后,子控件有一个 scrollView,它是完全为了实现下滚和滚到底部实现加载更多的监听.看到这,我相信任何一个有类似项目开发经验的人,都会感到很熟悉的.下拉刷新+下滑加载更多. 在 scrollV