子控件自動換行佈局

在這裏插入圖片描述

 /**
 * 功能描述:  子控件自動換行佈局
 */
public class SKUViewGroup extends ViewGroup implements LifecycleObserver {

    private Context context;
    private int itemDecorationHeight;
    private Adapter adapter;

    public SKUViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        if (context instanceof LifecycleOwner) {
            ((LifecycleOwner) context).getLifecycle().addObserver(this);
        }
    }

    @Override
    protected LayoutParams generateLayoutParams(
            LayoutParams p) {
        return new MarginLayoutParams(p);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new MarginLayoutParams(LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT);
    }

    /**
     * 負責設置子控件的測量模式和大小 根據所有子控件設置自己的寬和高
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 獲得它的父容器爲它設置的測量模式和大小
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

        // 如果是warp_content情況下,記錄寬和高
        int width = 0;
        int height = 0;
        /*
         * 記錄每一行的寬度,width不斷取最大寬度
         */
        int lineWidth = 0;
        /*
         * 每一行的高度,累加至height
         */
        int lineHeight = 0;

        int cCount = getChildCount();

        // 遍歷每個子元素
        for (int i = 0; i < cCount; i++) {
            View child = getChildAt(i);
            // 測量每一個child的寬和高
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            // 得到child的佈局管理器
            MarginLayoutParams lp = (MarginLayoutParams) child
                    .getLayoutParams();
            // 當前子空間實際佔據的寬度
            int childWidth = child.getMeasuredWidth() + lp.leftMargin
                    + lp.rightMargin;
            // 當前子空間實際佔據的高度
            int childHeight = child.getMeasuredHeight() + lp.topMargin
                    + lp.bottomMargin;
            /*
             * 如果加入當前child,則超出最大寬度,則的到目前最大寬度給width,類加height 然後開啓新行
             */
            if (lineWidth + childWidth > sizeWidth) {
                width = Math.max(lineWidth, childWidth);// 取最大的
                lineWidth = childWidth; // 重新開啓新行,開始記錄
                // 疊加當前高度,
                height += (lineHeight + itemDecorationHeight);
                // 開啓記錄下一行的高度
                lineHeight = childHeight;
            } else
            // 否則累加值lineWidth,lineHeight取最大高度
            {
                lineWidth += childWidth;
                lineHeight = Math.max(lineHeight, childHeight);
            }
            // 如果是最後一個,則將當前記錄的最大寬度和當前lineWidth做比較
            if (i == cCount - 1) {
                width = Math.max(width, lineWidth);
                height += lineHeight;
            }
        }
        setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ? sizeWidth
                : width, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight
                : height);
    }

    //居中對齊
    ArrayList<Integer> maxLinHeight = new ArrayList<>();

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int width = getWidth();
        int lineWidth = 0;
        int lineHeight = 0;
        maxLinHeight.clear();
        int cCount = getChildCount();

        int left = 0;
        int top = 0;

        // 遍歷所有的孩子
        for (int i = 0; i < cCount; i++) {
            View child = getChildAt(i);
            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
            int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
            int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;

            // 如果已經需要換行
            if (childWidth + lineWidth > width) {
                maxLinHeight.add(lineHeight);
                lineHeight = 0;// 重置行高
                lineWidth = 0;// 重置行寬
            }
            //如果不需要換行,則累加
            lineWidth += childWidth;
            lineHeight = Math.max(lineHeight, childHeight);
        }
        maxLinHeight.add(lineHeight);

        lineWidth = 0;
        int lines = 0;
        // 遍歷所有的孩子
        for (int i = 0; i < cCount; i++) {
            View child = getChildAt(i);
            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
            int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
            int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;

            // 如果已經需要換行
            if (childWidth + lineWidth > width) {
                lines++;
                top += (lineHeight + itemDecorationHeight);
                lineWidth = 0;// 重置行寬
                left = 0;
            }
            lineHeight = maxLinHeight.get(lines);

            if (child.getVisibility() != View.GONE) {
                //計算childView的佈局左上角和右下角
                int lc = left + lp.leftMargin;
                int tc = (int) (top + (lineHeight - childHeight) / 2f + lp.topMargin);
                int rc = lc + child.getMeasuredWidth();
                int bc = tc + child.getMeasuredHeight();

                child.layout(lc, tc, rc, bc);

                left += child.getMeasuredWidth() + lp.rightMargin + lp.leftMargin;
            }
            //如果不需要換行,則累加
            lineWidth += childWidth;
        }
    }

    public void setItemDecorationHeight(int ItemDecorationHeight) {
        itemDecorationHeight = ArmsUtils.dip2px(BaseApplication.getInstances(), ItemDecorationHeight);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)//和activity生命週期綁定後可用
    public void destroy() {
        if (context instanceof LifecycleOwner) {
            ((LifecycleOwner) context).getLifecycle().removeObserver(this);
        }
        context = null;
        if (adapter != null) {
            adapter.onRelease();
        }
    }

    public void setAdapter(Adapter adapter) {
        if (adapter != null) {
            this.adapter = adapter;
            adapter.bindGroup(this);
        }
    }

    public abstract static class Adapter<T, VH extends BaseHolder<T>> {
        SparseArray<ArrayList<SoftReference<VH>>> views = new SparseArray<>();
        private List<T> data;
        private SKUViewGroup group2;
        private OnItemClickListener<T> onItemClickListener;
        private OnSingleSelectedListener singleSelectedListener;
        private int lastChildViewsCount = 0;

        private void bindGroup(SKUViewGroup group2) {
            this.group2 = group2;
        }

        public void setData(List<T> data) {
            this.data = data;
            notifyDataSetChanged();
        }

        public void addItem(T item) {
            addItem(item, CheckValueUtils.checkList(data) ? data.size() : 0);
        }

        public void addItem(T item, int position) {
            if (data == null) {
                data = new ArrayList<>();
            }
            if (CheckValueUtils.checkListItem(data, position)) {
                data.add(position, item);
            } else {
                data.add(item);
            }
            addItemView(position);
        }

        public void removeItem(int position) {
            if (CheckValueUtils.checkListItem(data, position)) {
                data.remove(position);
                removeItemView(position);
            }
        }

        public void removeItem(T bean) {
            if (CheckValueUtils.checkListItem(data, bean)) {
                removeItemView(data.indexOf(bean));
                data.remove(bean);
            }
        }

        public T getItem(int position) {
            if (CheckValueUtils.checkListItem(data, position)) {
                return data.get(position);
            }
            return null;
        }

        public final void notifyItemChanged(int position) {
            VH itemVH = getItemVH(position);
            if (itemVH != null) {
                itemVH.setData(getItem(position), position);
            }
        }

        public final void notifyDataSetChanged() {
            int count = getCount();
            if (count != lastChildViewsCount) {
                onBindViewHolder(count);
            } else {
                for (int i = 0; i < count; i++) {
                    VH itemVH = getItemVH(i);
                    if (itemVH != null) {
                        itemVH.setData(getItem(i), i);
                    }
                }
            }
        }

        public int getCount() {
            return CheckValueUtils.checkList(data) ? data.size() : 0;
        }

        public abstract @LayoutRes
        int getLayoutRes(int viewType);

        public abstract VH onCreateViewHolder(View view, int viewType);

        private void onBindViewHolder(int count) {
            if (group2 != null) {
                group2.removeAllViews();
                if (CheckValueUtils.checkList(data)) {
                    for (int i = 0; i < count; i++) {
                        Integer viewType = getViewType(i);
                        VH vh = getItemVH(i);
                        if (vh == null) {
                            vh = createVH(i, viewType);
                        }
                        vh.setData(data.get(i), i);
                        group2.addView(vh.itemView);
                    }
                }
                lastChildViewsCount = count;
            }
        }

        private VH createVH(int i, Integer viewType) {
            VH vh;
            ArrayList<SoftReference<VH>> softReferences = checkViewList(viewType);
            if (CheckValueUtils.checkListItem(softReferences, i)) {
                SoftReference<VH> vhSoftReference = softReferences.get(i);
                if (vhSoftReference == null) {
                    vh = createVH(viewType, i, softReferences);
                } else {
                    vh = vhSoftReference.get();
                    if (vh == null) {
                        vh = createVH(viewType, i, softReferences);
                    }
                }
            } else {
                vh = createVH(viewType, i, softReferences);
            }
            return vh;
        }

        @NotNull
        private ArrayList<SoftReference<VH>> checkViewList(Integer viewType) {
            ArrayList<SoftReference<VH>> softReferences = views.get(viewType);
            if (softReferences == null) {
                softReferences = new ArrayList<>();
                views.put(viewType, softReferences);
            }
            return softReferences;
        }

        public void addItemView(int position) {
            int count = getCount();
            if (position >= count) {
                position = count - 1;
            }
            Integer viewType = getViewType(position);
            VH vh = createVH(viewType, position, checkViewList(viewType));
            vh.setData(getItem(position), position);
            if (group2 != null) {
                group2.addView(vh.itemView, position);
            }
        }

        public void removeItemView(int position) {
            ArrayList<SoftReference<VH>> softReferences = views.get(getViewType(position));
            if (CheckValueUtils.checkListItem(softReferences, position)) {
                softReferences.remove(position);
                if (group2 != null) {
                    group2.removeViewAt(position);
                }
            }
        }

        private SoftReference<VH> lastSelected;

        private VH createVH(int viewType, int position, ArrayList<SoftReference<VH>> views) {
            VH vh = onCreateViewHolder(LayoutInflater.from(group2.getContext())
                    .inflate(getLayoutRes(viewType), group2, false), viewType);
            SoftReference<VH> vhSoftReference = new SoftReference<>(vh);
            if (CheckValueUtils.checkListItem(views, position)) {
                views.add(position, vhSoftReference);
            } else {
                views.add(vhSoftReference);
            }
            vh.itemView.setOnClickListener(v -> {
                int index = views.indexOf(vhSoftReference);
                if (onItemClickListener != null) {
                    vh.setSelected(!vh.isSelected());
                    onItemClickListener.onClick(getItem(index), index);
                }
                if (singleSelectedListener != null) {
                    int lastSelectedPosition = views.indexOf(lastSelected);
                    if (lastSelected != null && lastSelected.get() != null) {
                        lastSelected.get().setSelected(false);
                    }
                    vh.setSelected(!vh.isSelected());
                    singleSelectedListener.OnSingleSelected(lastSelectedPosition, index);
                    lastSelected = vhSoftReference;
                }
            });
            return vh;
        }

        public VH getItemVH(int position) {
            Integer viewType = getViewType(position);
            ArrayList<SoftReference<VH>> softReferences = views.get(viewType);
            if (CheckValueUtils.checkListItem(softReferences, position)) {
                SoftReference<VH> vhSoftReference = softReferences.get(position);
                return vhSoftReference == null ? null : vhSoftReference.get();
            }
            return null;
        }

        protected Integer getViewType(int position) {
            return 0;
        }

        public void onRelease() {
            if (views != null) {
                views.clear();
            }
            views = null;
            group2 = null;
            if (data instanceof ArrayList) {
                data.clear();
            }
            data = null;
            onItemClickListener = null;
            singleSelectedListener = null;
        }

        public void setOnItemClickListener(OnItemClickListener<T> listener) {
            onItemClickListener = listener;
        }

        public void setOnSingleSelectedListener(OnSingleSelectedListener singleSelectedListener) {
            this.singleSelectedListener = singleSelectedListener;
        }

        public interface OnItemClickListener<T> {
            void onClick(T data, int position);
        }

        public interface OnSingleSelectedListener {
            void OnSingleSelected(int lastPosition, int currentPosition);
        }
    }
}
public abstract class BaseHolder<T> extends RecyclerView.ViewHolder implements View.OnClickListener {
    protected OnViewClickListener mOnViewClickListener = null;
    private Unbinder unbinder;
    private boolean isSelected;

    public boolean isSelected() {
        return isSelected;
    }

    public void setSelected(boolean selected) {
        isSelected = selected;
    }

    public BaseHolder(View itemView) {
        super(itemView);
        itemView.setOnClickListener(this);//點擊事件
        //綁定
        unbinder = ButterKnife.bind(this,itemView);
    }


    /**
     * 設置數據
     *
     * @param data
     * @param position
     */
    public abstract void setData(T data, int position);


    /**
     * 在 Activity 的 onDestroy 中使用 {@link DefaultAdapter#releaseAllHolder(RecyclerView)} 方法 (super.onDestroy() 之前)
     * {@link BaseHolder#onRelease()} 纔會被調用, 可以在此方法中釋放一些資源
     */
    public void onRelease() {
        if (unbinder != null && unbinder != Unbinder.EMPTY){
            unbinder.unbind();
            unbinder = null;
        }
    }

    @Override
    public void onClick(View view) {
        if (mOnViewClickListener != null) {
            mOnViewClickListener.onViewClick(view, this.getPosition());
        }
    }

    public interface OnViewClickListener {
        void onViewClick(View view, int position);
    }

    public void setOnItemClickListener(OnViewClickListener listener) {
        this.mOnViewClickListener = listener;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章