当前位置: 移动技术网 > IT编程>移动开发>Android > Android史上最强分割线全攻略

Android史上最强分割线全攻略

2018年09月17日  | 移动技术网IT编程  | 我要评论

孙政才的父亲,三多九如网,邓健泓女朋友

android史上最强分割线全攻略。说实话,分割线这个东西,真的太难太难了!!!

难在何处?难在用最对的方式去实现它!

1.view——管理代码不便,绘制开销大。非常非常不好

2.图片——修改不便,增加apk体积。非常非常不好

3.java代码——使用不便,增加代码量。非常非常不好

4.layer-list通过覆盖实现——过度绘制,修改不便。非常非常不好

5.shape——设置成background会自动填充,无法实现!

6.自定义控件——做模块化的时候,需要移植这个库。不太好

7.不充满的底部分割线的这种情况,实现起来更难——又一限制条件

所以他难

本人在探索了2个小时后,终于得出了结论

1.linearlayout——虽然background这个属性会自动填充,不能用,但是他有pider属性!

2.其他布局——自定义控件

3.recyclerview——itemdecoration

下面我将给出这些情况的代码,你可以直接拷去用。

代码原理就不解释了,太简单了。有问题留言。

linearlayout充满的底部分割线(其他方向的分割线也一样)




    
    


效果

\

linearlayout不充满的底部分割线






    
    


效果

\

其他布局:网上开源库很多,不过我不太喜欢用别人的库,所以自己实现了一个(实现了主流的relativelayout和framelayout)

attrs



    
        线到起始端的margin
        线到末端的margin
        线的宽度
        线的颜色
        线的位置:left、top、right、bottom
    

border relative layout

package com.example.filemanager;

import android.content.context;
import android.content.res.typedarray;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.util.attributeset;
import android.util.log;
import android.widget.relativelayout;

// todo: 2018/5/3 如果你想多弄几条线 或者位置有特殊需求 自己改写呗!

public class borderrelativelayout extends relativelayout {

    private static final string tag = "xbh";

    public borderrelativelayout(context context, attributeset attrs) {
        super(context, attrs);

        //params

        typedarray ta = context.obtainstyledattributes(attrs, r.styleable.borderrelativelayout);

        startmargin = ta.getdimension(r.styleable.borderrelativelayout_margin_start, 0);
        endmargin = ta.getdimension(r.styleable.borderrelativelayout_margin_end, 0);
        width = ta.getdimension(r.styleable.borderrelativelayout_width, 0);
        int color = ta.getcolor(r.styleable.borderrelativelayout_color, color.gray);
        position = ta.getstring(r.styleable.borderrelativelayout_position);

        ta.recycle();

        //init paint

        paint.setcolor(color);
    }

    //拿到绘制坐标:position、margin、width

    private static final string left = "left";
    private static final string top = "top";
    private static final string right = "right";
    private static final string bottom = "bottom";

    private float startmargin;
    private float endmargin;
    private float width;
    private final string position;

    private float left;
    private float top;
    private float right;
    private float bottom;

    @override
    protected void onlayout(boolean changed, int l, int t, int r, int b) {
        super.onlayout(changed, l, t, r, b);

        int w = getwidth();
        int h = getheight();

        if (left.equals(position)) {
            left = 0;
            top = startmargin;
            right = width;
            bottom = h - endmargin;
        } else if (top.equals(position)) {
            left = startmargin;
            top = 0;
            right = w - endmargin;
            bottom = width;
        } else if (right.equals(position)) {
            left = w - width;
            top = startmargin;
            right = w;
            bottom = h - endmargin;
        } else if (bottom.equals(position)) {
            left = startmargin;
            top = h - width;
            right = w - endmargin;
            bottom = h;
        }
    }

    //

    private final paint paint = new paint();

    @override
    protected void dispatchdraw(canvas canvas) {
        super.dispatchdraw(canvas);

        canvas.drawrect(left, top, right, bottom, paint);
    }
}

使用


测试了下非常好用。

frame layout你只需要改个名,继承自frame layout即可。

recyclerview

列表的情况上面就不适用了,因为最后一个item我们不期望有线。

rv.additemdecoration(new divideritemdecoration(activity, divideritemdecoration.vertical));

这行代码就会为我们处理的很好。

效果如下

\

如果我们对他默认的样式不满意呢?

我们可以通过setdrawable的方式去设置我们drawable文件夹下自己定义的线。但是这导致的后果是我们最后一个item也有了线。所以我们需要自定义itemdecoration。

(解决方案学习自:https://www.jianshu.com/p/26b33e1181e3 自己重写了一个divideritemdecoration)

static class divideritemdecoration extends recyclerview.itemdecoration {
    public static final int horizontal = linearlayout.horizontal;
    public static final int vertical = linearlayout.vertical;
    private static final string tag = "divideritem";
    private static final int[] attrs = new int[]{android.r.attr.listdivider};
    private drawable mdivider;
    private boolean misshowbottomdivider;
    /**
     * current orientation. either {@link #horizontal} or {@link #vertical}.
     */
    private int morientation;
    private final rect mbounds = new rect();

    public divideritemdecoration(context context, int orientation) {
        misshowbottomdivider = false;
        final typedarray a = context.obtainstyledattributes(attrs);
        mdivider = a.getdrawable(0);
        if (mdivider == null) {
            log.w(tag, "@android:attr/listdivider was not set in the theme used for this "
                    + "divideritemdecoration. please set that attribute all call setdrawable()");
        }
        a.recycle();
        setorientation(orientation);
    }

    /**
     * sets the orientation for this pider. this should be called if
     * {@link recyclerview.layoutmanager} changes orientation.
     *
     * @param orientation {@link #horizontal} or {@link #vertical}
     */
    public void setorientation(int orientation) {
        if (orientation != horizontal && orientation != vertical) {
            throw new illegalargumentexception(
                    "invalid orientation. it should be either horizontal or vertical");
        }
        morientation = orientation;
    }

    /**
     * sets the {@link drawable} for this pider.
     *
     * @param drawable drawable that should be used as a pider.
     */
    public void setdrawable(@nonnull drawable drawable) {
        if (drawable == null) {
            throw new illegalargumentexception("drawable cannot be null.");
        }
        mdivider = drawable;
    }

    @override
    public void ondraw(canvas c, recyclerview parent, recyclerview.state state) {
        if (parent.getlayoutmanager() == null || mdivider == null) {
            return;
        }
        if (morientation == vertical) {
            drawvertical(c, parent, state);
        } else {
            drawhorizontal(c, parent, state);
        }
    }

    private void drawvertical(canvas canvas, recyclerview parent, recyclerview.state state) {
        canvas.save();
        final int left;
        final int right;
        //noinspection androidlintnewapi - newapi lint fails to handle overrides.
        if (parent.getcliptopadding()) {
            left = parent.getpaddingleft();
            right = parent.getwidth() - parent.getpaddingright();
            canvas.cliprect(left, parent.getpaddingtop(), right,
                    parent.getheight() - parent.getpaddingbottom());
        } else {
            left = 0;
            right = parent.getwidth();
        }

        final int childcount = parent.getchildcount();
        final int lastposition = state.getitemcount() - 1;
        for (int i = 0; i < childcount; i++) {
            final view child = parent.getchildat(i);
            final int childrealposition = parent.getchildadapterposition(child);
            //misshowbottomdivider false的时候不绘制最后一个view的pider
            if (misshowbottomdivider || childrealposition < lastposition) {
                parent.getdecoratedboundswithmargins(child, mbounds);
                final int bottom = mbounds.bottom + math.round(child.gettranslationy());
                final int top = bottom - mdivider.getintrinsicheight();
                mdivider.setbounds(left, top, right, bottom);
                mdivider.draw(canvas);
            }
        }
        canvas.restore();
    }

    private void drawhorizontal(canvas canvas, recyclerview parent, recyclerview.state state) {
        canvas.save();
        final int top;
        final int bottom;
        //noinspection androidlintnewapi - newapi lint fails to handle overrides.
        if (parent.getcliptopadding()) {
            top = parent.getpaddingtop();
            bottom = parent.getheight() - parent.getpaddingbottom();
            canvas.cliprect(parent.getpaddingleft(), top,
                    parent.getwidth() - parent.getpaddingright(), bottom);
        } else {
            top = 0;
            bottom = parent.getheight();
        }

        final int childcount = parent.getchildcount();
        final int lastposition = state.getitemcount() - 1;
        for (int i = 0; i < childcount; i++) {
            final view child = parent.getchildat(i);
            final int childrealposition = parent.getchildadapterposition(child);
            //misshowbottomdivider false的时候不绘制最后一个view的pider
            if (misshowbottomdivider || childrealposition < lastposition) {
                parent.getlayoutmanager().getdecoratedboundswithmargins(child, mbounds);
                final int right = mbounds.right + math.round(child.gettranslationx());
                final int left = right - mdivider.getintrinsicwidth();
                mdivider.setbounds(left, top, right, bottom);
                mdivider.draw(canvas);
            }
        }
        canvas.restore();
    }

    @override
    public void getitemoffsets(rect outrect, view view, recyclerview parent,
                               recyclerview.state state) {
        if (mdivider == null) {
            outrect.set(0, 0, 0, 0);
            return;
        }
        if (morientation == vertical) {
            //parent.getchildcount() 不能拿到item的总数
            //https://stackoverflow.com/questions/29666598/android-recyclerview-finding-out-first
            // -and-last-view-on-itemdecoration
            int lastposition = state.getitemcount() - 1;
            int position = parent.getchildadapterposition(view);
            if (misshowbottomdivider || position < lastposition) {
                outrect.set(0, 0, 0, mdivider.getintrinsicheight());
            } else {
                outrect.set(0, 0, 0, 0);
            }
        } else {
            int lastposition = state.getitemcount() - 1;
            int position = parent.getchildadapterposition(view);
            if (misshowbottomdivider || position < lastposition) {
                outrect.set(0, 0, mdivider.getintrinsicwidth(), 0);
            } else {
                outrect.set(0, 0, 0, 0);
            }
        }
    }
}

自定义的样式




    
    

使用自定义的样式

//rv

recyclerview rv = (recyclerview) fvb(r.id.rv);
rv.setadapter(new adapter());
rv.setlayoutmanager(new linearlayoutmanager(activity));

divideritemdecoration decoration = new divideritemdecoration(activity, divideritemdecoration.vertical);
decoration.setdrawable(activity.getresources().getdrawable(r.drawable.border_bottom_not_full));
rv.additemdecoration(decoration);

大功告成。分割线的不同情形的最佳实现思路一直是让人头疼的地方,甚至在难以满足需求的时候忍不住直接用view。看了本文后,您可以开开心心地搞定分割线啦!

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网