安卓自定义控件-线性间距d性布局SpaceLinearLayout

安卓自定义控件-线性间距d性布局SpaceLinearLayout,第1张

安卓自定义控件-线性间距d性布局SpaceLinearLayout

在最新的安卓控件中可以使用约束布局来实现相同的效果,使用链的形式来实现
如下实例:

  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时)空间


手撸完成没多久 ,没有经过大量测试…

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5708399.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存