安卓流式布局

安卓流式布局,经常用在  历史搜索框、人物标签 等安卓功能中, 对于没有经验的同学来说,要自己写流式布局确实是一个难点,或者写出来的自定义布局的运行效率也不高,这里是我自己整理出的一个非常好的例子, 拿出来跟大家交流学习。

1、 FlowViewGroup 类的java代码如下

package com.snippet.worklearn;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class FlowViewGroup extends ViewGroup {
    private final static String TAG = "MyViewGroup2";

    private final static int VIEW_MARGIN = 0;

    public FlowViewGroup(Context context) {
        super(context);
    }

    public FlowViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.d(TAG, "widthMeasureSpec = " + widthMeasureSpec
                + " heightMeasureSpec" + heightMeasureSpec);

//        for (int index = 0; index < getChildCount(); index++) {
//            final View child = getChildAt(index);
//            // measure
//            child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
//        }

        int measureWidth = measureWidth(widthMeasureSpec);
        int measureHeight = measureHeight(heightMeasureSpec);
        
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(measureWidth, measureHeight);
        
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
        final int count = getChildCount();
        int row = 0;
        int left = arg1;
        int top = arg2;
        int right = arg3;
        int bottom = arg4;
        for (int i = 0; i < count; i++) {

            final View child = this.getChildAt(i);
            String text = ((TextView)child).getText().toString();
            
            Log.e(TAG,  text+" onLayout = " + arg0 + " left = " + arg1 + " top = " + arg2 + " right = " + arg3 + " botom = " + arg4);
            
            int width = child.getMeasuredWidth();
            int height = child.getMeasuredHeight();
            
            Log.e("----1-----",  "width="+width+"  , height="+height + " , measuredWidth="+ child.getMeasuredWidth() + " , paddingLeft="+child.getPaddingLeft()
                                            + " , paddingRight=" + child.getPaddingRight() );

            Log.e("----22--计算之前---",  "left="+left+ "  , right="+ right +"  , top="+top  );
            left += width + VIEW_MARGIN;
            top = row * (height + VIEW_MARGIN) + VIEW_MARGIN + height + arg2;
            
            Log.e("----33--计算之后---",  "left="+left+ "  , right="+ right +"  , top="+top  );
            
            if (left > right) {  
                left = width + VIEW_MARGIN + arg1;
                row++;
                top = row * (height + VIEW_MARGIN) + VIEW_MARGIN + height + arg2;
            }

            Log.e("----4444-----",  "left="+(left - width)+"  , top="+ (top - height) + " , right="+ left + " , bottom="+top );
            child.layout(left - width-arg1, top - height, left-arg1, top);
        }

    }
    
    private int measureWidth(int pWidthMeasureSpec) {
        int result = 0;
        int widthMode = MeasureSpec.getMode(pWidthMeasureSpec);// 得到模式
        int widthSize = MeasureSpec.getSize(pWidthMeasureSpec);// 得到尺寸

        switch (widthMode) {
        /**
         * mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY,
         * MeasureSpec.AT_MOST。
         *
         *
         * MeasureSpec.EXACTLY是精确尺寸,
         * 当我们将控件的layout_width或layout_height指定为具体数值时如andorid
         * :layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。
         *
         *
         * MeasureSpec.AT_MOST是最大尺寸,
         * 当控件的layout_width或layout_height指定为WRAP_CONTENT时
         * ,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可
         * 。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。
         *
         *
         * MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,
         * 通过measure方法传入的模式。
         */
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY:
            result = widthSize;
            break;
        }
        return result;
    }

    private int measureHeight(int pHeightMeasureSpec) {
        int result = 0;

        int heightMode = MeasureSpec.getMode(pHeightMeasureSpec);
        int heightSize = MeasureSpec.getSize(pHeightMeasureSpec);

        switch (heightMode) {
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY:
            result = heightSize;
            break;
        }
        return result;
    }

}


2、 xml文件中 使用方法如下:

<?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"
    android:paddingLeft="20dp"
    android:paddingRight="20dp" >
    
    <com.snippet.worklearn.FlowViewGroup
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible"
        android:background="#f0f" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/aaa"
            android:gravity="center_vertical"
            android:paddingLeft="20dp"
            android:paddingRight="10dp"
            android:text="两字" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/aaa"
            android:gravity="center"
            android:text="三个字" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/aaa"
            android:gravity="center"
            android:text="这是四字" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/aaa"
            android:gravity="center"
            android:text="五字超出没" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/aaa"
            android:gravity="center"
            android:text="梅凯三四五六七八" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/aaa"
            android:gravity="center"
            android:text="一" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/aaa"
            android:gravity="center"
            android:text="六字应该换行" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/aaa"
            android:gravity="center"
            android:text="七字肯定换行了" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/aaa"
            android:gravity="center"
            android:text="八字什么样子结果" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/aaa"
            android:gravity="center"
            android:text="一" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/aaa"
            android:gravity="center"
            android:text="呵呵" />
    </com.snippet.worklearn.MyViewGroup2>

</LinearLayout>


3、运行效果图:





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值