You can fold the Gridview

Realize the principle of

1, folding implementation

Override the setAdapter method of the GridView

    @Override
    public void setAdapter(ListAdapter adapter) {
        if (foldNm > 0) {
            // Fold
            adapter = new FoldViewGridAdapter(adapter, foldNm);
        }
        super.setAdapter(adapter);
    }
Copy the code

FoldViewGridAdapter FoldViewGridAdapter is a wrapper class that implements the wrapping of the current Adapter, overriding the getCount method as follows:

private class FoldViewGridAdapter implements WrapperListAdapter {...@Override
        public int getCount(a) {
            // if fn is less than 1, it is not folded
            if (fn < 0) {
                return adapter.getCount();
            } else {
                // If fn is greater than 0, fold
                if (expend) {
                    return adapter.getCount();
                } else {
                    returnMath.min(adapter.getCount(), fn * getNumColumns()); }}}@Override
        public ListAdapter getWrappedAdapter(a) {
            return this; }... }Copy the code

The initial value of FN is -1, that is, it is not folded. When the fn value is greater than 0, the folding judgment needs to be performed. If the folding is required, the return is returned

 return Math.min(adapter.getCount(), fn * getNumColumns());
Copy the code

The smallest of the two. Fn * getNumColumns() is the product of the number of rows displayed when folded and the number of columns displayed, i.e. the number of columns displayed.

2, How to add a ExpendControlView

The setAdapter method is also overridden to repackage the adapter.

HeaderViewGridAdapter headerViewGridAdapter = new HeaderViewGridAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);

Copy the code

The logic for adding a ExpendControlView is mainly in the HeaderViewGridAdapter, which implements the following:

1, How to make the added ExpendControlView exclusive to a row

    public void addExpendControlView(View v, Object data, boolean isSelectable, boolean isExpendControlView) {
 
        ViewGroup.LayoutParams lyp = v.getLayoutParams();

        FixedViewInfo info = new FixedViewInfo();
        FrameLayout fl = new FullWidthFixedViewLayout(getContext());

        if(lyp ! =null) {
            v.setLayoutParams(new FrameLayout.LayoutParams(lyp.width, lyp.height));
            fl.setLayoutParams(new LayoutParams(lyp.width, lyp.height));
        }
        fl.addView(v);
        info.view = v;
        info.viewContainer = fl;
        info.data = data;
        info.isSelectable = isSelectable;
        // Control whether it can be folded
        info.isExpendControlView = isExpendControlView;
        mFooterViewInfos.add(info);

        if(mAdapter ! =null) { ((HeaderViewGridAdapter) mAdapter).notifyDataSetChanged(); }}Copy the code

The addExpendControlView method creates an FL viewGroup and then adds the ControlView to the FL. FullWidthFixedViewLayout looks like this:

    private class FullWidthFixedViewLayout extends FrameLayout {

        public FullWidthFixedViewLayout(Context context) {
            super(context);
        }

        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            int realLeft = GridViewEnableFooter.this.getPaddingLeft() + getPaddingLeft();
            // Try to make where it should be, from left, full width
            if(realLeft ! = left) { offsetLeftAndRight(realLeft - left); }super.onLayout(changed, left, top, right, bottom);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int targetWidth = GridViewEnableFooter.this.getMeasuredWidth()
                    - GridViewEnableFooter.this.getPaddingLeft()
                    - GridViewEnableFooter.this.getPaddingRight();
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth,
                    MeasureSpec.getMode(widthMeasureSpec));
            super.onMeasure(widthMeasureSpec, heightMeasureSpec); }}Copy the code

Set the width to be the same as the GridView width on onLayout and onMeasure, and set the FL width to be the same as the GridView width.

2. Count calculation after adding ExpendControlView

Adding the ExpendControlView requires recalculating the getCount return value of the Adapter as follows:

        public int getCount(a) {
                return getExpendControlViewsCount() * mNumColumns + getAdapterAndPlaceHolderCount();
        }
Copy the code

Because a ExpendControlView a line, so need to be multiplied by the number of columns, getAdapterAndPlaceHolderCount method is as follows:

        private int getAdapterAndPlaceHolderCount(a) {
            return (int) (Math.ceil(1f * mAdapter.getCount() / mNumColumns) * mNumColumns);
        }
Copy the code

GetAdapterAndPlaceHolderCount used to replenish quantity, making the count number to an integer multiple of. If it is not an integer column, then the added ExpendControlView does not occupy a separate row, indicating a problem.

Rewrite the getView method.

The added ExpendControlView needs to be returned in getView, so you also need to override the getView method.

public View getView(int position, View convertView, ViewGroup parent) {

            // Adapter
            final int adjPosition = position - numHeadersAndPlaceholders;
            int adapterCount = 0;
            if(mAdapter ! =null) {
                adapterCount = getAdapterAndPlaceHolderCount();
                if (adjPosition < adapterCount) {
                    if (adjPosition < mAdapter.getCount()) {
                        return mAdapter.getView(adjPosition, convertView, parent);
                    } else {
                        if (convertView == null) {
                            convertView = new View(parent.getContext());
                        }
                        convertView.setVisibility(View.INVISIBLE);
                        convertView.setMinimumHeight(mRowHeight);
                        returnconvertView; }}}// ExpendControlView
            final int footerPosition = adjPosition - adapterCount;
            if (footerPosition < getCount()) {
                View footViewContainer = mFooterViewInfos
                        .get(footerPosition / mNumColumns).viewContainer;
                if (position % mNumColumns == 0) {
                    return footViewContainer;
                } else {
                    if (convertView == null) {
                        convertView = new View(parent.getContext());
                    }
                    // We need to do this because GridView uses the height of the last item
                    // in a row to determine the height for the entire row.
                    convertView.setVisibility(View.INVISIBLE);
                    convertView.setMinimumHeight(footViewContainer.getHeight());
                    returnconvertView; }}throw new ArrayIndexOutOfBoundsException(position);
        }
Copy the code

methods

1. Add bottom control View

public void addExpendControlView(View view)
Copy the code

2. Set the number of rows to display when folding

setFoldNum(int foldNm)
Copy the code

Used to set the number of rows to display when collapsing

Method of use

// Fold control View
gridView.addFooterView(LoadMoreView(this))

// Set the number of rows to collapse
gridView.setFoldNum(2) gridView.adapter = object : BaseAdapter() {... }Copy the code

LoadMoreView is the collapsible control view at the bottom. When adding your own control view, inherit the following interface

interface IExpendControl {
    /** * expand */
    fun expend(a)

    /** ** fold */
    fun fold(a)
}
Copy the code

Override the expend and fold methods, i.e., expand and fold, to complete the control.

class LoadMoreView @JvmOverloads constructor(
    context: Context.attrs: AttributeSet? = null
) : ConstraintLayout(context, attrs), IExpendControl {
    private var viewBinding: LoadMoreViewBinding =
        LoadMoreViewBinding.inflate(LayoutInflater.from(context), this)

    override fun expend(a) {
        // Operate while expanding
        viewBinding.loadMore.text = "Fold"
        viewBinding.arrow.setImageResource(R.drawable.up_arrow)
    }

    override fun fold(a) {
        // Operate while folding
        viewBinding.loadMore.text = "Unfold all"
        viewBinding.arrow.setImageResource(R.drawable.down_arrow)

    }
}
Copy the code

The source address

Github.com/hankinghu/E…

reference

Github.com/liaohuqiu/a…