/**
* 功能描述: 子控件自動換行佈局
*/
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;
}
}