转载请注明出处:王亟亟的大牛之路

之前也做过一些用TextView之类的记录ListView选项的东西。可是总认为好难看。发现个不错的实现就贴给大家。

项目文件夹



执行效果:

自己定义视图:

@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public class FlowLayout extends ViewGroup { private int mGravity = (isIcs() ? Gravity.START : Gravity.LEFT) | Gravity.TOP; private final List<List<View>> mLines = new ArrayList<List<View>>();
private final List<Integer> mLineHeights = new ArrayList<Integer>();
private final List<Integer> mLineMargins = new ArrayList<Integer>(); public FlowLayout(Context context) {
this(context, null);
} public FlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.FlowLayout, defStyle, 0); try {
int index = a.getInt(R.styleable.FlowLayout_android_gravity, -1);
if(index > 0) {
setGravity(index);
}
} finally {
a.recycle();
} } /**
* {@inheritDoc}
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec); int sizeWidth = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
int modeHeight = MeasureSpec.getMode(heightMeasureSpec); int width = 0;
int height = getPaddingTop() + getPaddingBottom(); int lineWidth = 0;
int lineHeight = 0; int childCount = getChildCount(); for(int i = 0; i < childCount; i++) { View child = getChildAt(i);
boolean lastChild = i == childCount - 1; if(child.getVisibility() == View.GONE) { if(lastChild) {
width = Math.max(width, lineWidth);
height += lineHeight;
} continue;
} measureChildWithMargins(child, widthMeasureSpec, lineWidth, heightMeasureSpec, height); LayoutParams lp = (LayoutParams) child.getLayoutParams(); int childWidthMode = MeasureSpec.AT_MOST;
int childWidthSize = sizeWidth; int childHeightMode = MeasureSpec.AT_MOST;
int childHeightSize = sizeHeight; if(lp.width == LayoutParams.MATCH_PARENT) {
childWidthMode = MeasureSpec.EXACTLY ;
childWidthSize -= lp.leftMargin + lp.rightMargin;
} else if(lp.width >= 0) {
childWidthMode = MeasureSpec.EXACTLY;
childWidthSize = lp.width;
} if(lp.height >= 0) {
childHeightMode = MeasureSpec.EXACTLY;
childHeightSize = lp.height;
} else if (modeHeight == MeasureSpec.UNSPECIFIED) {
childHeightMode = MeasureSpec.UNSPECIFIED;
childHeightSize = 0;
} child.measure(
MeasureSpec.makeMeasureSpec(childWidthSize, childWidthMode),
MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode)
); int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; if(lineWidth + childWidth > sizeWidth) { width = Math.max(width, lineWidth);
lineWidth = childWidth; height += lineHeight;
lineHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; } else {
lineWidth += childWidth;
lineHeight = Math.max(lineHeight, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
} if(lastChild) {
width = Math.max(width, lineWidth);
height += lineHeight;
} } width += getPaddingLeft() + getPaddingRight(); setMeasuredDimension(
(modeWidth == MeasureSpec.EXACTLY) ? sizeWidth : width,
(modeHeight == MeasureSpec.EXACTLY) ? sizeHeight : height);
} /**
* {@inheritDoc}
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) { mLines.clear();
mLineHeights.clear();
mLineMargins.clear(); int width = getWidth();
int height = getHeight(); int linesSum = getPaddingTop(); int lineWidth = 0;
int lineHeight = 0;
List<View> lineViews = new ArrayList<View>(); float horizontalGravityFactor;
switch ((mGravity & Gravity.HORIZONTAL_GRAVITY_MASK)) {
case Gravity.LEFT:
default:
horizontalGravityFactor = 0;
break;
case Gravity.CENTER_HORIZONTAL:
horizontalGravityFactor = .5f;
break;
case Gravity.RIGHT:
horizontalGravityFactor = 1;
break;
} for(int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if(child.getVisibility() == View.GONE) {
continue;
} LayoutParams lp = (LayoutParams) child.getLayoutParams(); int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
int childHeight = child.getMeasuredHeight() + lp.bottomMargin + lp.topMargin; if(lineWidth + childWidth > width) {
mLineHeights.add(lineHeight);
mLines.add(lineViews);
mLineMargins.add((int) ((width - lineWidth) * horizontalGravityFactor) + getPaddingLeft()); linesSum += lineHeight; lineHeight = 0;
lineWidth = 0;
lineViews = new ArrayList<View>();
} lineWidth += childWidth;
lineHeight = Math.max(lineHeight, childHeight);
lineViews.add(child);
} mLineHeights.add(lineHeight);
mLines.add(lineViews);
mLineMargins.add((int) ((width - lineWidth) * horizontalGravityFactor) + getPaddingLeft()); linesSum += lineHeight; int verticalGravityMargin = 0;
switch ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) ) {
case Gravity.TOP:
default:
break;
case Gravity.CENTER_VERTICAL:
verticalGravityMargin = (height - linesSum) / 2;
break;
case Gravity.BOTTOM:
verticalGravityMargin = height - linesSum;
break;
} int numLines = mLines.size(); int left;
int top = getPaddingTop(); for(int i = 0; i < numLines; i++) { lineHeight = mLineHeights.get(i);
lineViews = mLines.get(i);
left = mLineMargins.get(i); int children = lineViews.size(); for(int j = 0; j < children; j++) { View child = lineViews.get(j); if(child.getVisibility() == View.GONE) {
continue;
} LayoutParams lp = (LayoutParams) child.getLayoutParams(); // if height is match_parent we need to remeasure child to line height
if(lp.height == LayoutParams.MATCH_PARENT) {
int childWidthMode = MeasureSpec.AT_MOST;
int childWidthSize = lineWidth; if(lp.width == LayoutParams.MATCH_PARENT) {
childWidthMode = MeasureSpec.EXACTLY;
} else if(lp.width >= 0) {
childWidthMode = MeasureSpec.EXACTLY;
childWidthSize = lp.width;
} child.measure(
MeasureSpec.makeMeasureSpec(childWidthSize, childWidthMode),
MeasureSpec.makeMeasureSpec(lineHeight - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY)
);
} int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight(); int gravityMargin = 0; if(Gravity.isVertical(lp.gravity)) {
switch (lp.gravity) {
case Gravity.TOP:
default:
break;
case Gravity.CENTER_VERTICAL:
case Gravity.CENTER:
gravityMargin = (lineHeight - childHeight - lp.topMargin - lp.bottomMargin) / 2 ;
break;
case Gravity.BOTTOM:
gravityMargin = lineHeight - childHeight - lp.topMargin - lp.bottomMargin;
break;
}
} child.layout(left + lp.leftMargin,
top + lp.topMargin + gravityMargin + verticalGravityMargin,
left + childWidth + lp.leftMargin,
top + childHeight + lp.topMargin + gravityMargin + verticalGravityMargin); left += childWidth + lp.leftMargin + lp.rightMargin; } top += lineHeight;
} } @Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p);
} /**
* {@inheritDoc}
*/
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
} /**
* {@inheritDoc}
*/
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
} @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public void setGravity(int gravity) {
if(mGravity != gravity) {
if((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
gravity |= isIcs() ? Gravity.START : Gravity.LEFT;
} if((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
gravity |= Gravity.TOP;
} mGravity = gravity;
requestLayout();
}
} public int getGravity() {
return mGravity;
} /**
* @return <code>true</code> if device is running ICS or grater version of Android.
*/
private static boolean isIcs() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
} public static class LayoutParams extends MarginLayoutParams { public int gravity = -1; public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs); TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.FlowLayout_Layout); try {
gravity = a.getInt(R.styleable.FlowLayout_Layout_android_layout_gravity, -1);
} finally {
a.recycle();
}
} public LayoutParams(int width, int height) {
super(width, height);
} public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
} } }

分析:

这部分主要是呈现被选项的实现。伸手党能够无视

对象:

public class Filter_Object {
public String mName ;
public boolean mIsSelected ;
}

分析:填充是否被选,以及listView每一行的显示内容

MainActivity:

public class MainActivity extends AppCompatActivity {
private ListView mListView;
private ArrayList<Filter_Object> mArrFilter;
private ScrollView mScrollViewFilter;
private Filter_Adapter mFilter_Adapter ;
private FlowLayout mFlowLayoutFilter ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { getWindow().setStatusBarColor(getResources().getColor(R.color.themecolor));
} mArrFilter = new ArrayList<>(); String[] strArr = getResources().getStringArray(R.array.city); int lengthOfstrArr = strArr.length; for (int i = 0; i < lengthOfstrArr; i++) {
Filter_Object filter_object = new Filter_Object();
filter_object.mName = strArr[i];
filter_object.mIsSelected = false;
mArrFilter.add(filter_object);
} getSupportActionBar().setDisplayShowTitleEnabled(true);
getSupportActionBar().setTitle(getString(R.string.app_name)); mListView = (ListView) findViewById(R.id.listViewFilter);
mScrollViewFilter = (ScrollView)findViewById(R.id.scrollViewFilter);
//放置被选项的布局
mFlowLayoutFilter = (FlowLayout)findViewById(R.id.flowLayout); mFilter_Adapter = new Filter_Adapter(mArrFilter);
mListView.setAdapter(mFilter_Adapter);
}
public void addFilterTag() {
final ArrayList<Filter_Object> arrFilterSelected = new ArrayList<>(); mFlowLayoutFilter.removeAllViews(); int length = mArrFilter.size();
boolean isSelected = false;
for (int i = 0; i < length; i++) {
Filter_Object fil = mArrFilter.get(i);
if (fil.mIsSelected) {
isSelected = true;
arrFilterSelected.add(fil);
}
}
if (isSelected) {
mScrollViewFilter.setVisibility(View.VISIBLE);
} else {
mScrollViewFilter.setVisibility(View.GONE);
}
int size = arrFilterSelected.size();
LayoutInflater layoutInflater = (LayoutInflater)
this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); for (int i = 0; i < size; i++) {
View view = layoutInflater.inflate(R.layout.filter_tag_edit, null); TextView tv = (TextView) view.findViewById(R.id.tvTag);
LinearLayout linClose = (LinearLayout) view.findViewById(R.id.linClose);
final Filter_Object filter_object = arrFilterSelected.get(i);
linClose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//showToast(filter_object.name); int innerSize = mArrFilter.size();
for (int j = 0; j < innerSize; j++) {
Filter_Object mFilter_Object = mArrFilter.get(j);
if (mFilter_Object.mName.equalsIgnoreCase(filter_object.mName)) {
mFilter_Object.mIsSelected = false; }
}
addFilterTag();
mFilter_Adapter.updateListView(mArrFilter);
}
}); tv.setText(filter_object.mName);
int color = getResources().getColor(R.color.themecolor); View newView = view;
newView.setBackgroundColor(color); FlowLayout.LayoutParams params = new FlowLayout.LayoutParams(FlowLayout.LayoutParams.WRAP_CONTENT, FlowLayout.LayoutParams.WRAP_CONTENT);
params.rightMargin = 10;
params.topMargin = 5;
params.leftMargin = 10;
params.bottomMargin = 5; newView.setLayoutParams(params); mFlowLayoutFilter.addView(newView);
}
} public class Filter_Adapter extends BaseAdapter {
ArrayList<Filter_Object> arrMenu; public Filter_Adapter(ArrayList<Filter_Object> arrOptions) {
this.arrMenu = arrOptions;
} public void updateListView(ArrayList<Filter_Object> mArray) {
this.arrMenu = mArray;
notifyDataSetChanged();
} @Override
public int getCount() {
return this.arrMenu.size();
} @Override
public Object getItem(int position) {
return null;
} @Override
public long getItemId(int position) {
return 0;
} @Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.filter_list_item, null);
viewHolder = new ViewHolder();
viewHolder.mTtvName = (TextView) convertView.findViewById(R.id.tvName);
viewHolder.mTvSelected = (TextView) convertView.findViewById(R.id.tvSelected);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
final Filter_Object mService_Object = arrMenu.get(position);
viewHolder.mTtvName.setText(mService_Object.mName); if (mService_Object.mIsSelected) {
viewHolder.mTvSelected.setVisibility(View.VISIBLE);
} else {
viewHolder.mTvSelected.setVisibility(View.INVISIBLE);
}
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) { mService_Object.mIsSelected = !mService_Object.mIsSelected;
mScrollViewFilter.setVisibility(View.VISIBLE); addFilterTag();
notifyDataSetChanged();
}
});
return convertView;
} public class ViewHolder {
TextView mTtvName, mTvSelected; }
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
// getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId(); //noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
} return super.onOptionsItemSelected(item);
}
}

分析:

层次非常分明,从填充本地数据–>转加载ListView–>附加逻辑–>呈现。等流程思路非常清晰,可读性非常强。

详细使用,能够看源代码。一目了然。

源代码地址:http://yunpan.cn/cdbbFUd8rLFmJ 訪问password af07

android 自己定义ViewGroup实现可记载并呈现选择的ListView的更多相关文章

  1. Android 自己定义ViewGroup手把手教你实现ArcMenu

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/37567907 逛eoe发现这种UI效果,感觉非常不错,后来知道github上有这 ...

  2. Android自己定义ViewGroup打造各种风格的SlidingMenu

    看鸿洋大大的QQ5.0側滑菜单的视频课程,对于側滑的时的动画效果的实现有了新的认识,似乎打通了任督二脉.眼下能够实现随意效果的側滑菜单了.感谢鸿洋大大!! 鸿洋大大用的是HorizontalScrol ...

  3. Android 自己定义ViewGroup 实战篇 -&gt; 实现FlowLayout

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38352503 .本文出自[张鸿洋的博客] 1.概述 上一篇已经基本给大家介绍了怎 ...

  4. Android自己定义ViewGroup(二)——带悬停标题的ExpandableListView

    项目里要加一个点击可收缩展开的列表,要求带悬停标题,详细效果例如以下图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fon ...

  5. Android ViewDragHelper全然解析 自己定义ViewGroup神器

    转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/46858663. 本文出自:[张鸿洋的博客] 一.概述 在自己定义ViewGro ...

  6. Android自己定义组件系列【3】——自己定义ViewGroup实现側滑

    有关自己定义ViewGroup的文章已经非常多了,我为什么写这篇文章,对于刚開始学习的人或者对自己定义组件比較生疏的朋友尽管能够拿来主义的用了,可是要一步一步的实现和了解当中的过程和原理才干真真脱离别 ...

  7. 50个Android开发技巧(03 自己定义ViewGroup)

    问题:怎样创建一个例如以下图所看到的的布局?                图1 (原文地址:http://blog.csdn.net/vector_yi/article/details/244155 ...

  8. Android自己定义组件系列【1】——自己定义View及ViewGroup

    View类是ViewGroup的父类,ViewGroup具有View的全部特性.ViewGroup主要用来充当View的容器.将当中的View作为自己孩子,并对其进行管理.当然孩子也能够是ViewGr ...

  9. Android自己定义组件系列【4】——自己定义ViewGroup实现双側滑动

    在上一篇文章<Android自己定义组件系列[3]--自己定义ViewGroup实现側滑>中实现了仿Facebook和人人网的側滑效果,这一篇我们将接着上一篇来实现双面滑动的效果. 1.布 ...

随机推荐

  1. [ SCOI 2008 ] 着色方案

    \(\\\) \(Description\) 给出\(K\)种颜料各自的个数\(C_i\),每一个颜料只够涂一个格子,求将颜料用完,涂一排格子,每个格子只能涂一次的条件下,相邻两个格子的颜色互不相同的 ...

  2. P1257 平面上的最接近点对

    题目描述 给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的 输入输出格式 输入格式: 第一行:n:2≤n≤200000 接下来n行:每行两个实数:x y, ...

  3. 挂载硬盘,提示 mount: unknown filesystem type 'LVM2_member'的解决方案

    问题现象:由于重装linux,并且加了固态硬盘,直接将系统装在固态硬盘中.启动服务器的时候, 便看不到原来机械硬盘的挂载目录了,不知如何访问机械硬盘了.直接用命令 mount /dev/sda3 /s ...

  4. jQuery——val()、text()、html()

    val():获取标签中的value属性的值.带有参数是赋值(类比js中的value属性) text():获取双闭合标签中的文本值.(不识别标签)(类比innerText) html():获取双闭合标签 ...

  5. JS——鼠标在盒子中的坐标

    核心思想: 1.复杂版本:鼠标pageX.pageY的值减去盒子距离顶端的offsetLeft.offsetTop值就是鼠标在盒子中的坐标 2.简单版本:offsetX.offsetY就可获取鼠标相对 ...

  6. java实现搜索附近地点或人的功能

    前言 当前大多数app都有查找附近的功能, 简单的有查找周围的运动场馆, 复杂的有滴滴, 摩拜查找周围的车辆. 本文主要阐述查找附近地点的一般实现. 方案比较 方案1 (性能还不错) 数据库直接存经纬 ...

  7. shell编程之grep命令的使用

    大家在学习正则表达式之前,首先要明确一点,并把它牢牢记在心里,那就是: 在linux中,通配符是由shell解释的,而正则表达式则是由命令解释的,不要把二者搞混了.切记!!! 通常有三种文本处理工具/ ...

  8. Windows Server 2008无法远程连接

    Server 2008 R2依次配置好之后,重启发现总是远程桌面时而连接不上.具体现象如下: 偶尔可以通过桌面远程连接连接到Server.以为是防火墙的问题,各种设置——甚至关闭,依然无法连接.反复重 ...

  9. nginx设置绑定解析实现二级域名多域名

    apache(httpd)配置多个二级域名看这个链接:https://www.cnblogs.com/Crazy-Liu/p/10879928.html 网站的目录结构为/home/www├── bb ...

  10. 图像处理中创建CDib类时无法选择基类类型时怎么办

    图像处理中创建CDib类时无法选择基类类型时怎么办? 类的类型选择Generic Class 在下面的篮筐里输入CObject就行了