敞开生长之旅!这是我参与「日新计划 12 月更文挑战」的第15天

界面编码规划完成中,咱们必定会用到列表展现控件,大家必定用过ListView。后来google推出了RecycleView,帮咱们去做了很多优化(内置viewholder增加复用率、能够支撑局部改写、布局能够经过外层指定layout等),正常的运用,如下:

 	 MyRecycleViewAdapter adapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_decorator);
        Component component = new ConCreateComponent();
        ComponentImplA impl1 = new ComponentImplA(component);
        impl1.operation();
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            list.add("position " + i);
        }
        adapter = new MyRecycleViewAdapter(this);
        adapter.setData(list);
    }
    /**
     * 原始的yRecycleViewAdapter v1
     */
    public void buttonv1(View view) {
        findViewById(R.id.recycleview).setVisibility(View.VISIBLE);
        findViewById(R.id.wrapperR).setVisibility(View.GONE);
        RecyclerView recyclerView = findViewById(R.id.recycleview);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(adapter);
    }

可添加头尾的RecycleView的实现

可是RecycleView大家发现有一个问题,咱们假如想要为这个RecycleView增加自界说的头部view、尾部view的话,官方这个显着做不到,那这时咱们能够考虑用装修者形式或许承继去扩展一下。

规划UML图

首要咱们经过UML图,来规划一下,规划之前想一下,咱们是想要扩展RecyclerView.Adapter和RecyclerView,从而能够完成addHeadView、addFootView的功能,那么需求以下几步骤。

1)首要,因为RecyclerView.Adapter已经是一个抽象类接口,咱们自己承继与它,然后进行包装界说为WrapperRecyclerAdapter类 2)WrapperRecyclerAdapter必定要持有RecyclerView.Adapter的引证,所以需求有一个构造办法,将RecyclerView.Adapter的引证传递进来 3)因为WrapperRecyclerAdapter承继与RecyclerView.Adapter,必定要去完成要害的办法,onCreateViewHolder(创立viewitem的holder)、onBindViewHolder(viewholder数据绑定)、getItemCount(获取列表item的数量) 4)要害的一步来了,便是运用RecyclerView.Adapter、footviews、headviews,这三者组合,重写上面的三个重要办法,给列表相应位置创立对应的item

可添加头尾的RecycleView的实现

代码完成1

WrapperRecyclerAdapter

package com.itbird.design.decorator.recycleview;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
/**
 * RecyclerView.Adapter包装类,扩展完成headView、footView的增加
 * Created by itbird on 2022/6/10
 */
public class WrapperRecyclerAdapter extends RecyclerView.Adapter {
    RecyclerView.Adapter adapter;
    List<View> headViews = new ArrayList<>();
    List<View> footViews = new ArrayList<>();
    public WrapperRecyclerAdapter(RecyclerView.Adapter adapter) {
        this.adapter = adapter;
        adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
            @Override
            public void onChanged() {
                notifyDataSetChanged();
            }
        });
    }
    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int position) {
        //头部的,回来头部的viewholder
        if (position < headViews.size()) {
            return new WrapperViewHolder(headViews.get(position));
        }
        //adapter回来中心数据holder
        if (position >= headViews.size() && position < headViews.size() + adapter.getItemCount()) {
            return adapter.onCreateViewHolder(parent, adapter.getItemViewType(position - headViews.size()));
        }
        //尾部的,回来尾部的viewholder
        return new WrapperViewHolder(footViews.get(position - headViews.size() - adapter.getItemCount()));
    }
    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if (position < headViews.size() || position >= adapter.getItemCount() + headViews.size()) {
            return;
        }
        //头部和底部不需求做处理,只需求实在的adapter需求处理
        adapter.onBindViewHolder(holder, position - headViews.size());
    }
    @Override
    public int getItemViewType(int position) {
        return position;
    }
    @Override
    public int getItemCount() {
        return headViews.size() + footViews.size() + adapter.getItemCount();
    }
    public void addHeadView(View view) {
        if (!headViews.contains(view)) {
            headViews.add(view);
            notifyDataSetChanged();
        }
    }
    public void addFootView(View view) {
        if (!footViews.contains(view)) {
            footViews.add(view);
            notifyDataSetChanged();
        }
    }
    public void removeHeadView(View view) {
        if (headViews.contains(view)) {
            headViews.add(view);
            notifyDataSetChanged();
        }
    }
    public void removeFootView(View view) {
        if (footViews.contains(view)) {
            footViews.remove(view);
            notifyDataSetChanged();
        }
    }
    static class WrapperViewHolder extends RecyclerView.ViewHolder {
        public WrapperViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }
}

这时再去调用,发现就能够如下调用

    /**
     * 扩展的,能够增加头尾的recycleview v2
     */
    public void buttonv2(View view) {
        findViewById(R.id.recycleview).setVisibility(View.VISIBLE);
        findViewById(R.id.wrapperR).setVisibility(View.GONE);
        RecyclerView recyclerView = findViewById(R.id.recycleview);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        WrapperRecyclerAdapter wrapperRecyclerAdapter = new WrapperRecyclerAdapter(adapter);
        //这儿head为什么不会全屏,因为LayoutInflater需求parent才会全屏
        wrapperRecyclerAdapter.addHeadView(LayoutInflater.from(this).inflate(R.layout.layout_header_view, recyclerView, false));
        wrapperRecyclerAdapter.addFootView(new Button(this));
        recyclerView.setAdapter(wrapperRecyclerAdapter);
//        面向对象的六大基本准则,如同不符合最小知道准则,每次调用需求去new WrapperRecyclerAdapter这样的一个包装者,这必定是不对的,所以需求封装自己的recycleview
    }

看一下运转效果

可添加头尾的RecycleView的实现

代码完成2

这儿咱们发现一个问题,这样岂不是让开发者,每每次去运用的时分,new原始的adapter,还需求去new WrapperRecyclerAdapter,然后才能给recyclerView去setAdapter,面向对象的六大基本准则,如同不符合最小知道准则,每次调用需求去new WrapperRecyclerAdapter这样的一个包装者,这必定是不对的,所以需求封装自己的recycleview。

所以咱们做如下优化,将WrapperRecyclerAdapter的new操作,咱们能够放入recyclerView中,这样外界开发者只需求去关心WrapperRecycleView和RecyclerView.Adapter就能够了,关于开发者来讲,只需关心RecyclerView自界说就能够了。

自界说WrapperRecycleView,重写办法setAdapter,用于封装new WrapperRecyclerAdapter的操作

package com.itbird.design.decorator.recycleview;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
/**
 * 自界说WrapperRecycleView,重写办法setAdapter,用于封装new WrapperRecyclerAdapter的操作
 * Created by itbird on 2022/6/10
 */
public class WrapperRecycleView extends RecyclerView {
    WrapperRecyclerAdapter wrapperRecyclerAdapter;
    public WrapperRecycleView(@NonNull Context context) {
        super(context);
    }
    public WrapperRecycleView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    public WrapperRecycleView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    public void setAdapter(@Nullable Adapter adapter) {
        wrapperRecyclerAdapter = new WrapperRecyclerAdapter(adapter);
        super.setAdapter(wrapperRecyclerAdapter);
    }
    @Nullable
    @Override
    public Adapter getAdapter() {
        return wrapperRecyclerAdapter;
    }
    public void addHeadView(View view) {
        wrapperRecyclerAdapter.addHeadView(view);
    }
    public void addFootView(View view) {
        wrapperRecyclerAdapter.addFootView(view);
    }
    public void removeHeadView(View view) {
        wrapperRecyclerAdapter.removeHeadView(view);
    }
    public void removeFootView(View view) {
        wrapperRecyclerAdapter.removeFootView(view);
    }
}

调用一下

  /**
     * 将wrapperadapter的new操作,内部完成 v3
     * 封装的必要性,这样的话,只需求重视WrapperRecycleView,不再需求重视WrapperRecyclerAdapter
     */
    public void buttonv3(View view) {
        findViewById(R.id.wrapperR).setVisibility(View.VISIBLE);
        findViewById(R.id.recycleview).setVisibility(View.GONE);
        WrapperRecycleView wrapperRecycleView = findViewById(R.id.wrapperR);
        wrapperRecycleView.setLayoutManager(new LinearLayoutManager(this));
        wrapperRecycleView.setAdapter(adapter);
        wrapperRecycleView.addHeadView(LayoutInflater.from(this).inflate(R.layout.layout_header_view, wrapperRecycleView, false));
        wrapperRecycleView.addFootView(new Button(this));
        //这时再去考虑一个事情,咱们经过装修者形式把adapter封装了一层,假如adpater有数据更新,导致变动,这时会有问题吗?
        //这时会发现,并未更新,原因是装修类,并未做事情呼应
    }

是不是简略了很多。