Android开发经验谈

LayoutManager学习(四)代码重构

2019-06-19  本文已影响50人  刘景昌

要实现的效果我们在前三篇的文章中都已经实现了
但是没有可以一次写出来的完美的代码 我们的代码应该在重构中段前行
1.合并冗余代码
再次大家写代码的过程中总是会出现一些重复需要的代码,但是为了时间的缘故我们只是单纯的复制粘贴就好了 也没有去考虑一个良好的代码结构,这些的出现就是我们要处理的冗余代码
比如我完成这三的的时候冗余的代码就有

 /**
     * 获取RecyclerView的显示高度
     */
    public int getVerticalSpace() {
        return getHeight() - getPaddingTop() - getPaddingBottom();
    }

    /**
     * 获取RecyclerView的显示宽度
     */
    public int getHorizontalSpace() {
        return getWidth() - getPaddingLeft() - getPaddingRight();
    }


    @Override
    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
        return new RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT,
                RecyclerView.LayoutParams.WRAP_CONTENT);
    }

至于如何优化一般有两种方式
1.将重复代码写到工具类中
2.如果重复代码与本身的基类关联比较密切 我们应该新建一个基类 让他们来继承
这里我们采用第二种方式
这只完整的的最基础的基类

public class BaseLayoutManager extends RecyclerView.LayoutManager {

    @Override
    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
        return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    }
    /**
     * 获取RecyclerView的显示高度
     */
    public int getVerticalSpace() {
        return getHeight() - getPaddingTop() - getPaddingBottom();
    }

    /**
     * 获取RecyclerView的显示宽度
     */
    public int getHorizontalSpace() {
        return getWidth() - getPaddingLeft() - getPaddingRight();
    }

}

2.使用模板
我们可以使用模板设计模式 来是我们在整个实现过程中保持一个良好的思路
在做这件事情之前我们先要整理出自己的自定义LayoutManager的实现思路是什么 我们只要按照这个思路实现就行了 后面的人如果去看这个基类也能有一个良好的思路 在这三个实现类中我们要整理的主要部分是 onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state)
这个方法的实现里面
所以我们主要就是实现基类中的onLayoutChildren方法
我们设计的模板

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        if (getItemCount() <= 0 || state.isPreLayout()) {
            return;
        }
        //移除所有View
        removeAndRecycleAllViews(recycler);
        initItemView(recycler);
        List<T> itemViewList =  createItemViewInfoList();

        detachAndScrapAttachedViews(recycler);
        drawView(recycler, state, itemViewList);
    }
    
    @Override
    public void initItemView(RecyclerView.Recycler recycler) {

    }

    @Override
    public List<T> createItemViewInfoList() {
        return null;
    }

    @Override
    public void drawView(RecyclerView.Recycler recycler, RecyclerView.State state, List<T> itemViewList) {

    }
    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        if (getItemCount() <= 0 || state.isPreLayout()) {
            return;
        }
        //移除所有View
        removeAndRecycleAllViews(recycler);
        initItemView(recycler);
        List<T> itemViewList =  createItemViewInfoList();
        detachAndScrapAttachedViews(recycler);
        drawView(recycler, state, itemViewList);
    }
    
    @Override
    public void initItemView(RecyclerView.Recycler recycler) {

    }

    @Override
    public List<T> createItemViewInfoList() {
        return null;
    }

    @Override
    public void drawView(RecyclerView.Recycler recycler, RecyclerView.State state, List<T> itemViewList) {

    }

    @Override
    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
        if (getItemCount() <= 0 || state.isPreLayout()) {
            return;
        }
        //移除所有View
        removeAndRecycleAllViews(recycler);
        initItemView(recycler);
        List<T> itemViewList =  createItemViewInfoList();
      // 在布局之前,将所有的子 View 先 Detach 掉,放入到 Scrap 缓存中
        detachAndScrapAttachedViews(recycler);
        drawView(recycler, state, itemViewList);
    }
    
    @Override
    public void initItemView(RecyclerView.Recycler recycler) {

    }

    @Override
    public List<T> createItemViewInfoList() {
        return null;
    }

    @Override
    public void drawView(RecyclerView.Recycler recycler, RecyclerView.State state, List<T> itemViewList) {

    }

设计的接口

public interface LayoutManagerInterface<T> {
    /***
     * 初始化绘制参数
     * @param recycler
     */
    void initItemView(RecyclerView.Recycler recycler) ;

    /***
     * 创建绘制界面所需要的bean
     * @return
     */
    List<T> createItemViewInfoList() ;

    /***
     * 实际绘制
     * @param recycler
     * @param state
     * @param itemViewList
     */
     void drawView(RecyclerView.Recycler recycler, RecyclerView.State state, List<T> itemViewList) ;
}

在这做的时候有两个想法
1.使用泛型是每个实现类都自己的实体类

  1. 写一个包含所有的属性的bean 每个实现类都使用这实体类
    虽然感觉两个都可以,但是最终选择了 1 至于为什么 我也不知道直觉吧
    这样我们最基础的模板就大好了 我们就可以去改在具体的实现类了 后面我们发现有什么共有的特征可以在玩基类里面加
    我在这里只是说以下一个的改造 感觉写的时候第一个最差也最容易就改第一个吧。
    首先我们应该有一个控制类来控制list的信息的配置和list的创建并和View的绘制个里所以有了TanTanControl类
public class TanTanControl {

    private int count = 4;
    private float scale = 0.05f;
    private int translateY = 100;

    public TanTanControl(int count, float scale, int translateY) {
        this.count = count;
        this.scale = scale;
        this.translateY = translateY;
    }

    public int getCount() {
        return count;
    }

    public float getScale() {
        return scale;
    }

    public int getTranslateY() {
        return translateY;
    }

    public List<TanTanBean> createItemViewInfoList(int itemCount) {
        int lastPosition;
        if (itemCount < count) {
            lastPosition = 0;
        } else {
            lastPosition = itemCount - count;
        }
        List<TanTanBean> tanTanBeanList = new ArrayList<>();
        for (int position = lastPosition; position < itemCount; position++) {
            TanTanBean tanTanBean = new TanTanBean();
            int level = itemCount - position - 1;
            tanTanBean.setLevel(level);
            //设置每层的Scale和translationY
            if (level > 0) {
                //设置每一层X方向的缩小
                tanTanBean.setScaleX(1 - scale * level);
                if (level < count - 1) {
                    //Y需要缩小的和位移
                    tanTanBean.setTranslateY(translateY * level);
                    tanTanBean.setScaleY(1 - scale * level);
                } else {
                    //不需要缩小和位移只需要和前一层保持一致
                    tanTanBean.setTranslateY(translateY * (level - 1));
                    tanTanBean.setScaleY(1 - scale * (level - 1));
                }
            }
            tanTanBeanList.add(tanTanBean);
        }

        return tanTanBeanList;
    }

}

在这里面负责逻辑和默认参数的配置
而新的Layoutmanager只负责View层的绘制

public class TanTanLayoutManager extends BaseLayoutManager<TanTanBean> {
    TanTanControl tanTanControl;

    public TanTanLayoutManager(TanTanControl tanTanControl) {
        this.tanTanControl = tanTanControl;
    }

    @Override
    public void initItemView(RecyclerView.Recycler recycler) {

    }

    @Override
    public List<TanTanBean> createItemViewInfoList() {
        return tanTanControl.createItemViewInfoList(getItemCount());
    }

    @Override
    public void drawView(RecyclerView.Recycler recycler, RecyclerView.State state, List<TanTanBean> itemViewList) {
        int itemCount = getItemCount();
        if (itemCount < 1) {
            return;
        }
        for (int i = 0; i < itemViewList.size(); i++) {
            TanTanBean tanTanBean = itemViewList.get(i);
            View view = recycler.getViewForPosition(itemCount - tanTanBean.getLevel() - 1);
            addView(view);
            measureChildWithMargins(view, 0, 0);
            int widthSpace = getWidth() - getDecoratedMeasuredWidth(view);
            int heightSpace = getHeight() - getDecoratedMeasuredHeight(view);
            layoutDecoratedWithMargins(view, widthSpace / 2, heightSpace / 4,
                    widthSpace / 2 + getDecoratedMeasuredWidth(view),
                    heightSpace / 4 + getDecoratedMeasuredHeight(view));
            if (tanTanBean.getLevel() > 0) {
                view.setScaleX(tanTanBean.getScaleX());
                view.setTranslationY(tanTanBean.getTranslateY());
                view.setScaleY(tanTanBean.getScaleY());
            }
        }
    }
}

他们两件中间联系的纽带实体类

public class TanTanBean {
    private int translateY;
    private  float scaleX;
    private  float scaleY;
    private int level;
}

这样改造基本就完成了 然后就是抽时间吧另外两个也改了

修改后demo :https://github.com/525642022/LayoutManagerTest

上一篇 下一篇

猜你喜欢

热点阅读