首页 > 代码库 > 子控件根据父控件行宽自动换行---LineWrapLayout实现
子控件根据父控件行宽自动换行---LineWrapLayout实现
一些带搜索功能的app,在搜索栏下面一般会提供一些关键字供用户选择。
也可以根据用户输入的文字,在下一次使用的时候该文字出现在常用关键字里面,只要轻轻一点就可以搜索了,无需再次输入。
关键字可以动态添加,这就要考虑换行的问题了
废话不多说,先上效果图:
先定义2个自定义属性
<declare-styleable name="linewarplayout"> <attr name="magin" format="integer" /> <attr name="itemBg" format="reference"></attr> </declare-styleable>
magin:关键字之间间隔
itemBg:关键字的背景
.......
算了不写了
上代码
package com.tang.linewraplayout; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class LineWrapLayout extends ViewGroup { private int magin = 20;//每个VIEW之间的间距 private List<List<View>> mAllChildViews = new ArrayList<List<View>>();//所有子控件 private List<Integer> mLineHeight =new ArrayList<Integer>();//每一行的高度 public interface OnItemClickListener//点击事件接口 { public void onClick(View view); } private OnItemClickListener clickListener; public void setOnItemClickListener(OnItemClickListener clickListener) { this.clickListener=clickListener; } private Context context; private int bgId=0;//textview背景ID public LineWrapLayout(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.linewarplayout); magin = a.getInt(R.styleable.linewarplayout_magin, 20); bgId = a.getResourceId(R.styleable.linewarplayout_itemBg, R.drawable.text_bg); } /** * 关键字数据 * @param data */ public void setData(List<String> data) { Log.i("AAA", "setData:"+data.size()); for(int i = 0;i<data.size();i++) { TextView textView = new TextView(context); textView.setText(data.get(i)); if(bgId!=0) textView.setBackgroundResource(bgId); textView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub clickListener.onClick(v); } }); this.addView(textView); } } @Override protected ViewGroup.LayoutParams generateDefaultLayoutParams() { return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); //取得控件的宽高 int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); //测量模式 int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); int mWidth = 0; int mHeight = 0; int lineWidth = 0; int lineHeight = 0; int mCount = getChildCount(); for (int i = 0; i < mCount; i++) { View child = getChildAt(i); measureChild(child, widthMeasureSpec, heightMeasureSpec); MarginLayoutParams lp = (MarginLayoutParams) child .getLayoutParams(); // 当前子控件占据的宽度和高度+子控件之间的间距 int childWidth = child.getMeasuredWidth() + magin +lp.leftMargin + lp.rightMargin; int childHeight = child.getMeasuredHeight() + magin +lp.topMargin + lp.bottomMargin; int temp = lineWidth + childWidth; if (temp <= sizeWidth) { //当新加的子控件宽度+当前行所有子控件之和还小于父控件宽度 //说明当前行还可以添加 lineWidth += childWidth; lineHeight = Math.max(lineHeight, childHeight); } else { //否则的话就要增加一行了 mWidth = Math.max(lineWidth, mWidth);// 取最大的 lineWidth = childWidth; // 重新开启新行,开始记录 // 加上当前高度, mHeight += lineHeight; // 开启记录下一行的高度 lineHeight = childHeight; } } //加上最后一行的高度 mHeight += lineHeight; mWidth = Math.max(mWidth, lineWidth); mHeight =Math.max(mHeight, lineHeight); setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ? sizeWidth : mWidth, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight : mHeight); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { mAllChildViews.clear(); mLineHeight.clear(); int width = getWidth(); int lineWidth = 0; int lineHeight = 0; // 每一行所有的childView List<View> lineViews = new ArrayList<View>(); int mCount = getChildCount(); Log.i("AAA", "mCount:"+mCount); // 遍历所有 for (int i = 0; i < mCount; i++) { View child = getChildAt(i); MarginLayoutParams lp = (MarginLayoutParams) child .getLayoutParams(); int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); int temp = childWidth + magin +lp.leftMargin+ lp.rightMargin + lineWidth; // 如果不需要换行 if (temp <= width) { lineWidth = temp; lineHeight = Math.max(lineHeight, childHeight + magin +lp.topMargin + lp.bottomMargin); lineViews.add(child); } else { // 记录这一行的高度 mLineHeight.add(lineHeight); // 将当前行的View保存,然后new 一个List保存下一行的child mAllChildViews.add(lineViews); lineViews = new ArrayList<View>(); lineViews.add(child); lineHeight = childHeight + magin +lp.topMargin+ lp.bottomMargin; lineWidth = childWidth + magin +lp.leftMargin+ lp.rightMargin; } } // 将最后一行加入队列 mLineHeight.add(lineHeight); mAllChildViews.add(lineViews); int left = 0; int top = 0; // 总行数 int count = mAllChildViews.size(); for (int i = 0; i < count; i++) { lineViews = mAllChildViews.get(i); lineHeight = mLineHeight.get(i); // 遍历当前行所有的View for (int j = 0; j < lineViews.size(); j++) { View child = lineViews.get(j); MarginLayoutParams lp = (MarginLayoutParams) child .getLayoutParams(); int lc = left + magin+lp.leftMargin; int tc = top + magin+lp.topMargin; int rc =lc + child.getMeasuredWidth(); int bc = tc + child.getMeasuredHeight(); child.layout(lc, tc, rc, bc); left += child.getMeasuredWidth() + lp.rightMargin+lp.leftMargin + magin; } left = 0; top += lineHeight; } } }
在onMeasure中对控件的高度和宽度进行计算
在onlayout中将子控件添加到指定的位置
使用setData将关键字数据集传递进来,生成子控件,添加点击事件
使用OnItemClickListener接口将子控件的点击事件传递出去
注意:若前者计算不正确的话子控件会漏掉一部分,显示不完全
使用:
<com.tang.linewraplayout.LineWrapLayout android:id="@+id/linewarplayout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/editText1" android:layout_below="@+id/editText1" android:layout_marginTop="15dp" linewarplayout:magin="20" linewarplayout:itemBg="@drawable/text_bg" > </com.tang.linewraplayout.LineWrapLayout>
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); LineWrapLayout layout = (LineWrapLayout) findViewById(R.id.linewarplayout); List<String>list = new ArrayList<String>(); String s=""; for(int i=0;i<9;i++) { s=s+"X"; String temp ="第"+(i+1)+"个:"+s; list.add(temp); } layout.setData(list); layout.setOnItemClickListener(new OnItemClickListener() { @Override public void onClick(View view) { // TODO Auto-generated method stub Log.i("AAA", ((TextView)view).getText().toString()); } }); }
代码下载:http://download.csdn.net/detail/tangnengwu/7822189
子控件根据父控件行宽自动换行---LineWrapLayout实现
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。