自定义Linearlayout,实现dividerPaddingLeft和dividerPaddingRight

         在项目中经常会用到分割线,很多应用的“我的”模块,都会用到分割线,那么怎么优雅的实现这种很简单的效果呢?

         实现它一般最简单最麻烦的方法可能就是Linearlayout然后里面每个子view之间用一个view,然后设置背景,然后高度设置为1px了,其实,最初我也这么搞过,但是效率实在是低呀,后来知道了Linearlayout自己就有实现分割线的属性了,就是一个divider属性,它指向的是一个drawable文件了,既然是drawable,那么可定制化的东西就很多了,然后showDividers是指这个分割线显示的位置,同样可能用到的一个属性就是dividerPadding了,它是指代分割线距离边界的距离,距离两边都有哦,说的这些大家也都知道。

         以前这么用也没什么问题,后来ui设计师又要仿照ios了,ios的分割线一般都是距离左边有一段距离,而对于右边则是顶边的,那么单纯的设置dividerPadding是不可以的,有的同学说,我可以直接给该linearlayout设置一个paddingLeft呀,这样子也没问题,可是要是要加点击效果呢?设置了paddingLeft后,点击效果背景变化也会距离左边一段距离呀。那怎么办?难道又要回到设置通过设置空view然后设置背景的老路了吗?其实此刻想的是要是Android提供一个dividerPaddingLeft该多好呀。可是现实是人家没提供。

        然后就去看看linearlayout中关于dividerPadding到底是怎么处理的吧,或许我们可以自定义下呢,首先是可以看到通过mDividerPadding = a.getDimensionPixelSize(R.styleable.LinearLayout_dividerPadding, 0);通过这个属性获取到xml中设置的dividerPadding的值,然后看到用到的地方就是两个地方:

void drawHorizontalDivider(Canvas canvas, int top) {
        mDivider.setBounds(getPaddingLeft() + mDividerPadding, top, getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
        mDivider.draw(canvas);
    }

       可以看到一个是绘制竖直方向上的分割线,一个则是绘制水平方向上的分割线的,其实我们要是能把这两个方法给改了,那就不达到了我们变相设置dividerPaddingLeft的效果了嘛,其实我们只需要将第一个方法drawHorizontalDivider改为如下方式就好了,

void drawHorizontalDivider(Canvas canvas, int top) {
        mDivider.setBounds(getPaddingLeft() + mDividerPadding, top, getWidth() - getPaddingRight(), top + mDividerHeight);
        mDivider.draw(canvas);
    }

只修要将mDivider的setBounds的第三个设置right方向距离的参数改下就好了。然后我们的目标明确了,接下来就是实现了,哈哈哈。

        看了下,linearlayout的代码还是蛮多的,都有2000行了,一般咱们都是继承LinearLayout,然后重写里面的方法就好了,对于我们就是重写,drawHorizontalDivider和drawVerticalDivider两个方法了,但是它俩不是public的,故而无法被重写了。所以只能想想别的方法了,然后就想到了鸿洋大神之前写过一篇兼容android3.0以下实现linearlayout的分隔线的文章,原文地址是:http://blog.csdn.net/lmj623565791/article/details/42407923,我就在这个基础上进行了修改;请看下面代码:

/**
 * 能够设置left或者right的dividerpadding的线性布局
 * Created by hexiaopang on 2017/8/14 14:50.
 */
public class CustomerDividerPaddingLinearLayout extends LinearLayout {

    private static final int[] LL = new int[]{ //
            android.R.attr.divider,//
            android.R.attr.showDividers,//
            android.R.attr.dividerPadding //
    };

    private static final int LL_DIVIDER = 0;
    private static final int LL_SHOW_DIVIDER = 1;
    private static final int LL_DIVIDER_PADDING = 2;

    /**
     * android:dividers
     */
    private Drawable mDivider;
    /**
     * 对应:android:showDividers
     */
    private int mShowDividers;
    /**
     * 对应:android:dividerPadding
     */
    private int mDividerPadding;
    /**
     * 自定义的只有左侧有的dividerPaddingLeft
     */
    private int mDividerPaddingLeft;
    /**
     * 自定义的只有右侧有的dividerPaddingRight
     */
    private int mDividerPaddingRight = 0;

    private int mDividerWidth;
    private int mDividerHeight;

    public CustomerDividerPaddingLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray a = context.obtainStyledAttributes(attrs, LL);
        setDividerDrawable(a.getDrawable(CustomerDividerPaddingLinearLayout.LL_DIVIDER));
        mDividerPadding = a.getDimensionPixelSize(LL_DIVIDER_PADDING, 0);
        mDividerPaddingLeft = mDividerPadding;
        mShowDividers = a.getInteger(LL_SHOW_DIVIDER, SHOW_DIVIDER_NONE);
        a.recycle();
    }

    /**
     * 设置分隔元素,初始化宽高等
     */
    public void setDividerDrawable(Drawable divider) {
        if (divider == mDivider) {
            return;
        }
        mDivider = divider;
        if (divider != null) {
            mDividerWidth = divider.getIntrinsicWidth();
            mDividerHeight = divider.getIntrinsicHeight();
        } else {
            mDividerWidth = 0;
            mDividerHeight = 0;
        }
        setWillNotDraw(divider == null);
        requestLayout();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //将分隔元素的宽高转化为对应的margin
        setChildrenDivider();
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    /**
     * 将分隔元素的宽高转化为对应的margin
     */
    protected void setChildrenDivider() {
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            //遍历每个子View
            View child = getChildAt(i);
            //拿到索引
            final int index = indexOfChild(child);
            //方向
            final int orientation = getOrientation();

            final LayoutParams params = (LayoutParams) child.getLayoutParams();
            //判断是否需要在子View左边绘制分隔
            if (hasDividerBeforeChildAt(index)) {
                if (orientation == VERTICAL) {
                    //如果需要,则设置topMargin为分隔元素的高度(垂直时)
                    params.topMargin = mDividerHeight;
                } else {
                    //如果需要,则设置leftMargin为分隔元素的宽度(水平时)
                    params.leftMargin = mDividerWidth;
                }
            }
        }
    }

    /**
     * 判断是否需要在子View左边绘制分隔
     */
    public boolean hasDividerBeforeChildAt(int childIndex) {
        if (childIndex == 0 || childIndex == getChildCount()) {
            return false;
        }
        if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {
            boolean hasVisibleViewBefore = false;
            for (int i = childIndex - 1; i >= 0; i--) {
                //当前index的前一个元素不为GONE则认为需要
                if (getChildAt(i).getVisibility() != GONE) {
                    hasVisibleViewBefore = true;
                    break;
                }
            }
            return hasVisibleViewBefore;
        }
        return false;
    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (mDivider != null) {
            if (getOrientation() == VERTICAL) {
                //绘制垂直方向的divider
                drawDividersVertical(canvas);
            } else {
                //绘制水平方向的divider
                drawDividersHorizontal(canvas);
            }
        }
        super.onDraw(canvas);
    }

    /**
     * 绘制水平方向的divider
     * @param canvas
     */
    private void drawDividersHorizontal(Canvas canvas) {
        final int count = getChildCount();
        //遍历所有的子View
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child != null && child.getVisibility() != GONE) {
                //如果需要绘制divider
                if (hasDividerBeforeChildAt(i)) {
                    final android.widget.LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) child
                            .getLayoutParams();
                    //得到开始的位置,getLeft为当前View的左侧,而左侧有margin,所以之差为divider绘制的开始区域
                    final int left = child.getLeft() - lp.leftMargin/*
																	 * -
																	 * mDividerWidth
																	 */;
                    //绘制divider
                    drawVerticalDivider(canvas, left);
                }
            }
        }
    }

    /**
     * 绘制divider,根据left,水平方向绘制
     * @param canvas
     * @param left
     */
    public void drawVerticalDivider(Canvas canvas, int left) {
        //设置divider的范围
        mDivider.setBounds(left, getPaddingTop() + mDividerPaddingLeft, left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPaddingRight);
        //绘制
        mDivider.draw(canvas);
    }

    private void drawDividersVertical(Canvas canvas) {
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);

            if (child != null && child.getVisibility() != GONE) {
                if (hasDividerBeforeChildAt(i)) {
                    final android.widget.LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) child
                            .getLayoutParams();
                    final int top = child.getTop() - lp.topMargin/*
																 * -
																 * mDividerHeight
																 */;
                    drawHorizontalDivider(canvas, top);
                }
            }
        }
    }

    private void drawHorizontalDivider(Canvas canvas, int top) {
        mDivider.setBounds(getPaddingLeft() + mDividerPaddingLeft, top, getWidth() - getPaddingRight() - mDividerPaddingRight, top + mDividerHeight);
        mDivider.draw(canvas);
    }

    //设置dividerpaddingleft
    public void setDividerPaddingLeft(int dividerPaddingLeft){
        this.mDividerPaddingLeft = dividerPaddingLeft;
    }

    //设置dividerpaddingright
    public void setDividerPaddingRight(int dividerPaddingRight){
        this.mDividerPaddingRight = dividerPaddingRight;
    }
}
        其实,我改的主要也就是我上面说的那两个方法了,并且提供了两个方法setDividerPaddingLeft和setDividerPaddingRight了, 用于设置分割线的paddingleft和paddingright。
同样在用这个自定义布局时候,xml中设置的dividerPadding则只对于mDividerPaddingLeft有效了,mDividerPaddingRight默认是0,如果想要其有值,则需要调用setDividerPaddingRight单独设置了。
       以上就是本次内容,有问题欢迎批评指正。




你可能感兴趣的:(android小日子记录)