900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > android自定义view流布局 Android控件进阶-自定义流式布局和热门标签控件

android自定义view流布局 Android控件进阶-自定义流式布局和热门标签控件

时间:2022-10-16 10:09:31

相关推荐

android自定义view流布局 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等方法。具体核心实现代码如下:packagecom.czm.flowlayout;

importjava.util.ArrayList;

importjava.util.List;

importandroid.content.Context;

importandroid.util.AttributeSet;

importandroid.view.View;

importandroid.view.ViewGroup;

/**

*

*@authorcaizhiming

*

*/

publicclassXCFlowLayoutextendsViewGroup{

@Override

protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){

//TODOAuto-generatedmethodstub

//父控件传进来的宽度和高度以及对应的测量模式

intsizeWidth=MeasureSpec.getSize(widthMeasureSpec);

intmodeWidth=MeasureSpec.getMode(widthMeasureSpec);

intsizeHeight=MeasureSpec.getSize(heightMeasureSpec);

intmodeHeight=MeasureSpec.getMode(heightMeasureSpec);

//如果当前ViewGroup的宽高为wrap_content的情况

intwidth=0;//自己测量的宽度

intheight=0;//自己测量的高度

//记录每一行的宽度和高度

intlineWidth=0;

intlineHeight=0;

//获取子view的个数

intchildCount=getChildCount();

for(inti=0;i

Viewchild=getChildAt(i);

//测量子View的宽和高

measureChild(child,widthMeasureSpec,heightMeasureSpec);

//得到LayoutParams

MarginLayoutParamslp=(MarginLayoutParams)child.getLayoutParams();

//子View占据的宽度

intchildWidth=child.getMeasuredWidth()+lp.leftMargin+lp.rightMargin;

//子View占据的高度

intchildHeight=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);

}

@Override

protectedvoidonLayout(booleanchanged,intl,intt,intr,intb){

//TODOAuto-generatedmethodstub

mAllChildViews.clear();

mLineHeight.clear();

//获取当前ViewGroup的宽度

intwidth=getWidth();

intlineWidth=0;

intlineHeight=0;

//记录当前行的view

ListlineViews=newArrayList();

intchildCount=getChildCount();

for(inti=0;i

Viewchild=getChildAt(i);

MarginLayoutParamslp=(MarginLayoutParams)child.getLayoutParams();

intchildWidth=child.getMeasuredWidth();

intchildHeight=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=newArrayList();

}

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的位置

intleft=0;

inttop=0;

//获取行数

intlineCount=mAllChildViews.size();

for(inti=0;i

//当前行的views和高度

lineViews=mAllChildViews.get(i);

lineHeight=mLineHeight.get(i);

for(intj=0;j

Viewchild=lineViews.get(j);

//判断是否显示

if(child.getVisibility()==View.GONE){

continue;

}

MarginLayoutParamslp=(MarginLayoutParams)child.getLayoutParams();

intcLeft=left+lp.leftMargin;

intcTop=top+lp.topMargin;

intcRight=cLeft+child.getMeasuredWidth();

intcBottom=cTop+child.getMeasuredHeight();

//进行子View进行布局

child.layout(cLeft,cTop,cRight,cBottom);

left+=child.getMeasuredWidth()+lp.leftMargin+lp.rightMargin;

}

left=0;

top+=lineHeight;

}

}

}

2.相关的布局文件:

引用自定义控件:

xmlns:tools="/tools"

android:id="@+id/container"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/flowlayout"

android:layout_width="match_parent"

android:layout_height="match_parent">

三、使用该自定义布局控件类

最后,如何使用该自定义的热门标签控件类呢?很简单,请看下面实例代码:packagecom.czm.flowlayout;

importandroid.app.Activity;

importandroid.graphics.Color;

importandroid.os.Bundle;

importandroid.view.ViewGroup.LayoutParams;

importandroid.view.ViewGroup.MarginLayoutParams;

importandroid.widget.TextView;

/**

*

*@authorcaizhiming

*

*/

publicclassMainActivityextendsActivity{

privateStringmNames[]={

"welcome","android","TextView",

"apple","jamy","kobebryant",

"jordan","layout","viewgroup",

"margin","padding","text",

"name","type","search","logcat"

};

privateXCFlowLayoutmFlowLayout;

@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initChildViews();

}

privatevoidinitChildViews(){

//TODOAuto-generatedmethodstub

mFlowLayout=(XCFlowLayout)findViewById(R.id.flowlayout);

MarginLayoutParamslp=newMarginLayoutParams(

LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);

lp.leftMargin=5;

lp.rightMargin=5;

lp.topMargin=5;

lp.bottomMargin=5;

for(inti=0;i

TextViewview=newTextView(this);

view.setText(mNames[i]);

view.setTextColor(Color.WHITE);

view.setBackgroundDrawable(getResources().getDrawable(R.drawable.textview_bg));

mFlowLayout.addView(view,lp);

}

}

}

四、项目代码目录结构图

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。