Android中常見的熱門標籤的流式布局的實現,android標籤布局

來源:互聯網
上載者:User

Android中常見的熱門標籤的流式布局的實現,android標籤布局

一、概述:
在日常的app使用中,我們會在android 的app中看見 熱門標籤等自動換行的流式布局,今天,我們就來看看如何

自訂一個類似熱門標籤那樣的流式布局吧(源碼下載在下面最後給出)

類似的自訂布局。下面我們就來詳細介紹流式布局的應用特點以及用的的技術點:

1.流式布局的特點以及應用情境
    特點:當上面一行的空間不夠容納新的TextView時候,
    才開闢下一行的空間

  原理圖:

  

    情境:主要用於關鍵詞搜尋或者熱門標籤等情境
2.自訂ViewGroup,重點重寫下面兩個方法

    1、onMeasure:測量子view的寬高,設定自己的寬和高

    2、onLayout:設定子view的位置

    onMeasure:根據子view的布局檔案中屬性,來為子view設定測量模式和測量值
    測量=測量模式+測量值;

    測量模式有3種:
    EXACTLY:表示設定了精確的值,一般當childView設定其寬、高為精確值、match_parent時,ViewGroup會將其設定為EXACTLY;
    AT_MOST:表示子布局被限制在一個最大值內,一般當childView設定其寬、高為wrap_content時,ViewGroup會將其設定為AT_MOST;
    UNSPECIFIED:表示子布局想要多大就多大,一般出現在AadapterView的item的heightMode中、ScrollView的childView的heightMode中;此種模式比較少見。
3.LayoutParams
    ViewGroup LayoutParams :每個 ViewGroup 對應一個 LayoutParams; 即 ViewGroup -> LayoutParams
    getLayoutParams 不知道轉為哪個對應的LayoutParams ,其實很簡單,就是如下:
    子View.getLayoutParams 得到的LayoutParams對應的就是 子View所在的父控制項的LayoutParams;
    例如,LinearLayout 裡面的子view.getLayoutParams ->LinearLayout.LayoutParams
    所以 咱們的FlowLayout 也需要一個LayoutParams,由於上面的是子View的 margin,
    所以應該使用MarginLayoutParams。即FlowLayout->MarginLayoutParams

4.最後來看看實現的最終:


二、熱門標籤的流式布局的實現:

1. 自訂熱門標籤的ViewGroup實現

  根據上面的技術分析,自訂類繼承於ViewGroup,並重寫 onMeasure和onLayout等方法。具體實現代碼如下:

package com.czm.flowlayout;import java.util.ArrayList;import java.util.List;import android.content.Context;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;/** *  * @author caizhiming * @created on 2015-4-13 */public class XCFlowLayout extends ViewGroup{    //儲存所有子View    private List<List<View>> mAllChildViews = new ArrayList<>();    //每一行的高度    private List<Integer> mLineHeight = new ArrayList<>();        public XCFlowLayout(Context context) {        this(context, null);        // TODO Auto-generated constructor stub    }    public XCFlowLayout(Context context, AttributeSet attrs) {        this(context, attrs, 0);        // TODO Auto-generated constructor stub    }    public XCFlowLayout(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        // TODO Auto-generated constructor stub    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        // TODO Auto-generated method stub                //父控制項傳進來的寬度和高度以及對應的測量模式        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);                //如果當前ViewGroup的寬高為wrap_content的情況        int width = 0;//自己測量的 寬度        int height = 0;//自己測量的高度        //記錄每一行的寬度和高度        int lineWidth = 0;        int lineHeight = 0;                //擷取子view的個數        int childCount = getChildCount();        for(int i = 0;i < childCount; i ++){            View child = getChildAt(i);            //測量子View的寬和高            measureChild(child, widthMeasureSpec, heightMeasureSpec);            //得到LayoutParams            MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();            //子View佔據的寬度            int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;            //子View佔據的高度            int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;            //換行時候            if(lineWidth + childWidth > sizeWidth){                //對比得到最大的寬度                width = Math.max(width, lineWidth);                //重設lineWidth                lineWidth = childWidth;                //記錄行高                height += lineHeight;                lineHeight = childHeight;            }else{//不換行情況                //疊加行寬                lineWidth += childWidth;                //得到最大行高                lineHeight = Math.max(lineHeight, childHeight);            }            //處理最後一個子View的情況            if(i == childCount -1){                width = Math.max(width, lineWidth);                height += lineHeight;            }        }        //wrap_content        setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width,                modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height);        super.onMeasure(widthMeasureSpec, heightMeasureSpec);    }        @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        // TODO Auto-generated method stub        mAllChildViews.clear();        mLineHeight.clear();        //擷取當前ViewGroup的寬度        int width = getWidth();                int lineWidth = 0;        int lineHeight = 0;        //記錄當前行的view        List<View> lineViews = new ArrayList<View>();        int childCount = getChildCount();        for(int i = 0;i < childCount; i ++){            View child = getChildAt(i);            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();            int childWidth = child.getMeasuredWidth();            int childHeight = child.getMeasuredHeight();                        //如果需要換行            if(childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width){                //記錄LineHeight                mLineHeight.add(lineHeight);                //記錄當前行的Views                mAllChildViews.add(lineViews);                //重設行的寬高                lineWidth = 0;                lineHeight = childHeight + lp.topMargin + lp.bottomMargin;                //重設view的集合                lineViews = new ArrayList();            }            lineWidth += childWidth + lp.leftMargin + lp.rightMargin;            lineHeight = Math.max(lineHeight, childHeight + lp.topMargin + lp.bottomMargin);            lineViews.add(child);        }        //處理最後一行        mLineHeight.add(lineHeight);        mAllChildViews.add(lineViews);                //設定子View的位置        int left = 0;        int top = 0;        //擷取行數        int lineCount = mAllChildViews.size();        for(int i = 0; i < lineCount; i ++){            //當前行的views和高度            lineViews = mAllChildViews.get(i);            lineHeight = mLineHeight.get(i);            for(int j = 0; j < lineViews.size(); j ++){                View child = lineViews.get(j);                //判斷是否顯示                if(child.getVisibility() == View.GONE){                    continue;                }                MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();                int cLeft = left + lp.leftMargin;                int cTop = top + lp.topMargin;                int cRight = cLeft + child.getMeasuredWidth();                int cBottom = cTop + child.getMeasuredHeight();                //進行子View進行布局                child.layout(cLeft, cTop, cRight, cBottom);                left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;            }            left = 0;            top += lineHeight;        }            }    /**     * 與當前ViewGroup對應的LayoutParams     */    @Override    public LayoutParams generateLayoutParams(AttributeSet attrs) {        // TODO Auto-generated method stub                return new MarginLayoutParams(getContext(), attrs);    }}

2.相關的布局檔案:

引用自訂控制項:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/container"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <com.czm.flowlayout.XCFlowLayout        android:id="@+id/flowlayout"        android:layout_width="match_parent"        android:layout_height="match_parent" >    </com.czm.flowlayout.XCFlowLayout></RelativeLayout>

TextView的樣式檔案:

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android" >    <solid android:color="#666666" />    <corners android:radius="10dp" />    <padding         android:left="5dp"        android:right="5dp"        android:top="5dp"        android:bottom="5dp"         /></shape>

三、使用該自訂布局控制項類

最後,如何使用該自訂的熱門標籤控制項類呢?很簡單,請看下面執行個體代碼:

package com.czm.flowlayout;import android.app.Activity;import android.graphics.Color;import android.os.Bundle;import android.view.ViewGroup.LayoutParams;import android.view.ViewGroup.MarginLayoutParams;import android.widget.TextView;/** *  * @author caizhiming * @created on 2015-4-13 */public class MainActivity extends Activity {    private String mNames[] = {            "welcome","android","TextView",            "apple","jamy","kobe bryant",            "jordan","layout","viewgroup",            "margin","padding","text",            "name","type","search","logcat"    };    private XCFlowLayout mFlowLayout;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);                initChildViews();            }    private void initChildViews() {        // TODO Auto-generated method stub        mFlowLayout = (XCFlowLayout) findViewById(R.id.flowlayout);        MarginLayoutParams lp = new MarginLayoutParams(                LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);        lp.leftMargin = 5;        lp.rightMargin = 5;        lp.topMargin = 5;        lp.bottomMargin = 5;        for(int i = 0; i < mNames.length; i ++){            TextView view = new TextView(this);            view.setText(mNames[i]);            view.setTextColor(Color.WHITE);            view.setBackgroundDrawable(getResources().getDrawable(R.drawable.textview_bg));            mFlowLayout.addView(view,lp);        }    }}

四、源碼下載

最後給出源碼的下載:http://download.csdn.net/detail/jczmdeveloper/8590113

此源碼下載完之後,往往有個要點我們容易忽略,那就是源碼的安全性問題,此處可點擊行動裝置 App安全智慧型服務供應商愛加密的Android加密,源碼保護!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.