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

之前也做过一些用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 访问密码 af07

更多相关文章

  1. ADB源码分析(一)
  2. Android(安卓)Timer 分析
  3. android使用viewpager计算偏移量实现选项卡功能
  4. SEAndroid安全机制框架分析
  5. Picasso源码分析
  6. android framework 源码流程分析技巧
  7. 分析各种Android设备屏幕分辨率与适配 - 使用大量真实安卓设备采
  8. Android_adb shell am/pm使用
  9. okhttp源码分析

随机推荐

  1. Android更新UI用法AsyncTask
  2. Android入门
  3. Android(安卓)自定义view 基础篇(一)
  4. Android查看源码
  5. Android第一讲笔记(常用控件以及线性布局
  6. 在Android中使用FFmpeg(android studio环
  7. Android通过http协议POST传输方式
  8. Android(安卓)O添加Settings设置项的方法
  9. 【Android导航决】环境插件配置笔记
  10. Android之SeekBar的简单使用