![子控件自动换行布局_第1张图片](http://img.e-com-net.com/image/info8/4dfddd94c32d4a2b8a565558bd8e237f.jpg)
/**
* 功能描述: 子控件自动换行布局
*/
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 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> {
SparseArray>> views = new SparseArray<>();
private List data;
private SKUViewGroup group2;
private OnItemClickListener onItemClickListener;
private OnSingleSelectedListener singleSelectedListener;
private int lastChildViewsCount = 0;
private void bindGroup(SKUViewGroup group2) {
this.group2 = group2;
}
public void setData(List 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> softReferences = checkViewList(viewType);
if (CheckValueUtils.checkListItem(softReferences, i)) {
SoftReference 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> checkViewList(Integer viewType) {
ArrayList> 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> softReferences = views.get(getViewType(position));
if (CheckValueUtils.checkListItem(softReferences, position)) {
softReferences.remove(position);
if (group2 != null) {
group2.removeViewAt(position);
}
}
}
private SoftReference lastSelected;
private VH createVH(int viewType, int position, ArrayList> views) {
VH vh = onCreateViewHolder(LayoutInflater.from(group2.getContext())
.inflate(getLayoutRes(viewType), group2, false), viewType);
SoftReference 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> softReferences = views.get(viewType);
if (CheckValueUtils.checkListItem(softReferences, position)) {
SoftReference 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 listener) {
onItemClickListener = listener;
}
public void setOnSingleSelectedListener(OnSingleSelectedListener singleSelectedListener) {
this.singleSelectedListener = singleSelectedListener;
}
public interface OnItemClickListener {
void onClick(T data, int position);
}
public interface OnSingleSelectedListener {
void OnSingleSelected(int lastPosition, int currentPosition);
}
}
}
public abstract class BaseHolder 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;
}
}