1. 程式人生 > >android 自己定義ViewGroup實現可記載並呈現選擇的ListView

android 自己定義ViewGroup實現可記載並呈現選擇的ListView

uml tla asc tdi long getmenu selected support appcompat

轉載請註明出處:王亟亟的大牛之路

之前也做過一些用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(); } } /** * [email protected]} */ @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); } /** * [email protected]} */ @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); } /** * [email protected]} */ @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(getContext(), attrs); } /** * [email protected]} */ @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