在最新的安卓控件中可以使用约束布局来实现相同的效果,使用链的形式来实现
如下实例:
app:layout_constraintHorizontal_chainStyle="packed" ....
等实现多个view排列间距的形式 但是不能满足我不同的需求来排列;
下面我自己手撸了一个:可以实现多个view 排列自由组合
package com.kyli.base.view; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.util.SparseIntArray; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import androidx.annotation.Nullable; public class SpaceLinearLayout extends LinearLayout { private static final String TAG="SpaceLinearLayout"; private SpaceSetting spaceSetting; private SparseIntArray spaceSize = new SparseIntArray(); public void setSpaceSetting(SpaceSetting spaceSetting) { this.spaceSetting = spaceSetting; } public interface SpaceSetting { int setSpace(int position, int totalSpace, int onlySpace); } public SpaceLinearLayout(Context context) { super(context); } public SpaceLinearLayout(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public SpaceLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (spaceSetting == null) return; if (getOrientation() == HORIZONTAL) onLayoutWidth(l, t, r, b); else onLayoutHeight(l, t, r, b); } private void onLayoutWidth(int l, int t, int r, int b) { int left = l + getPaddingStart(); for (int i = 0; i < getChildCount(); i++) { left += spaceSize.get(i); View v = getChildAt(i); int measuredWidth = v.getMeasuredWidth(); int measuredHeight = v.getMeasuredHeight(); ViewGroup.MarginLayoutParams layoutParams = (MarginLayoutParams) v.getLayoutParams(); if (v.getVisibility() != GONE) { left += layoutParams.getMarginStart(); Log.e(TAG,"[left:]"+left); v.layout(left, v.getTop(), left + measuredWidth, v.getBottom()); left += layoutParams.getMarginEnd(); left+=measuredWidth; } } } private void onLayoutHeight(int l, int t, int r, int b) { int top = l + getPaddingTop(); for (int i = 0; i < getChildCount(); i++) { top += spaceSize.get(i); View v = getChildAt(i); int measuredWidth = v.getMeasuredWidth(); int measuredHeight = v.getMeasuredHeight(); ViewGroup.MarginLayoutParams layoutParams = (MarginLayoutParams) v.getLayoutParams(); if (v.getVisibility() != GONE) { top += layoutParams.topMargin; v.layout(v.getLeft(), top, v.getRight(), top + measuredHeight); top += layoutParams.bottomMargin; top+=measuredHeight; } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (spaceSetting == null) return; if (getOrientation() == HORIZONTAL) { computerForWidth(widthMeasureSpec, heightMeasureSpec); } else { computerForHeight(widthMeasureSpec, heightMeasureSpec); } } private void computerForWidth(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); Log.e(TAG,"[Parent:Width]="+width); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int totalSpace = width - getPaddingStart() - getPaddingEnd();// int childHieght = 0; int childWidth = 0;//所有空间的宽度和 for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); int measuredWidth = child.getMeasuredWidth(); int measuredHeight = child.getMeasuredHeight(); MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams(); int totalMarginW = layoutParams.getMarginStart() + layoutParams.getMarginEnd(); int totalMarginH = layoutParams.topMargin + layoutParams.bottomMargin; childHieght = Math.max(childHieght, measuredHeight + totalMarginH); if (child.getVisibility() != GONE) { childWidth += totalMarginW; childWidth += measuredWidth; totalSpace -= measuredWidth; totalSpace -= totalMarginW; } if (totalSpace <= 0) { totalSpace = 0; break; } } if (totalSpace == 0) return; int consumeSpace = 0;//消费空间 for (int i = 0; i < getChildCount(); i++) { int iNeedSpace = spaceSetting.setSpace(i, totalSpace, totalSpace - consumeSpace); if (iNeedSpace <= totalSpace - consumeSpace) { consumeSpace += iNeedSpace; spaceSize.put(i, iNeedSpace); }else{ spaceSize.put(i, totalSpace - consumeSpace); consumeSpace =totalSpace; } } int lastSpace = spaceSetting.setSpace(getChildCount(), totalSpace, totalSpace - consumeSpace); if (lastSpace <= totalSpace - consumeSpace) { consumeSpace += lastSpace; spaceSize.put(getChildCount(), lastSpace); }else{ spaceSize.put(getChildCount(),totalSpace - consumeSpace); consumeSpace =totalSpace; } if (totalSpace - consumeSpace <= 0) { Log.e("SpaceLinearLayout", "space <=0"); } setMeasuredDimension( widthMode != MeasureSpec.EXACTLY ? consumeSpace + childWidth + getPaddingStart() + getPaddingEnd() : width, heightMode != MeasureSpec.EXACTLY ? childHieght + getPaddingTop() + getPaddingBottom() : height); } private void computerForHeight(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int totalSpace = height - getPaddingTop() - getPaddingBottom();// int childHieght = 0; int childWidth = 0;//找出最大宽度 for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); int measuredWidth = child.getMeasuredWidth(); int measuredHeight = child.getMeasuredHeight(); MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams(); int totalMarginW = layoutParams.getMarginStart() + layoutParams.getMarginEnd(); int totalMarginH = layoutParams.topMargin + layoutParams.bottomMargin; childWidth = Math.max(childWidth, measuredWidth + totalMarginW); if (child.getVisibility() != GONE) { childHieght += totalMarginH; childHieght += measuredHeight; totalSpace -= measuredHeight; totalSpace -= totalMarginH; } if (totalSpace <= 0) { totalSpace = 0; break; } } if (totalSpace == 0) return; int consumeSpace = 0; for (int i = 0; i < getChildCount(); i++) { int iNeedSpace = spaceSetting.setSpace(i, totalSpace, totalSpace - consumeSpace); if (iNeedSpace <= totalSpace - consumeSpace) { consumeSpace += iNeedSpace; spaceSize.put(i, iNeedSpace); }else{ spaceSize.put(i, totalSpace - consumeSpace); consumeSpace = totalSpace; } } int lastSpace = spaceSetting.setSpace(getChildCount(), totalSpace, totalSpace - consumeSpace); if (lastSpace <= totalSpace - consumeSpace) { consumeSpace += lastSpace; spaceSize.put(getChildCount(), lastSpace); }else{ spaceSize.put(getChildCount(), totalSpace - consumeSpace); consumeSpace=totalSpace; } if (totalSpace - consumeSpace <= 0) { Log.e("SpaceLinearLayout", "space <=0"); } setMeasuredDimension( widthMode != MeasureSpec.EXACTLY ? childWidth + getPaddingStart() + getPaddingEnd() : width, heightMode != MeasureSpec.EXACTLY ? consumeSpace + childHieght + getPaddingTop() + getPaddingBottom() : height); } }
使用时xml中和linearlayout 线性布局完全一样 没有任何不同;
只是需要在java中去自由组合我们的间距:
viewBind.spaceLinear.setSpaceSetting(new SpaceLinearLayout.SpaceSetting() { @Override public int setSpace(int position, int totalSpace, int onlySpace) { int childCount = viewBind.spaceLinear.getChildCount(); return totalSpace / (childCount+1); } });
需要说明的是:
该接口中三个参数:
position 每个view的下标 和最后一个view后面的下标
(设计是按照每个view之前会出现一个间距 并且最后一个view的后面也会出现一个)
totalSpace 表示总的间距
onlyspace 表示剩余可用的(position时)空间
手撸完成没多久 ,没有经过大量测试…
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)