android 自己定义ViewGroup实现可记载并呈现选择的ListView

亦余心之所善兮,虽九死其犹未悔。这篇文章主要讲述android 自己定义ViewGroup实现可记载并呈现选择的ListView相关的知识,希望能为你提供帮助。
转载请注明出处:王亟亟的大牛之路
之前也做过一些用TextView之类的记录ListView选项的东西。可是总认为好难看。发现个不错的实现就贴给大家。

项目文件夹

android 自己定义ViewGroup实现可记载并呈现选择的ListView

文章图片

执行效果:
android 自己定义ViewGroup实现可记载并呈现选择的ListView

文章图片

【android 自己定义ViewGroup实现可记载并呈现选择的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





    推荐阅读