RecyclerView新增頭腳佈局,使用SwipeRefreshLayout的實現
阿新 • • 發佈:2019-02-07
上篇文章記錄了將viewpager抽取出來,那麼這篇文章我們繼續來實現,將viewpager做為頭佈局新增給RecyclerView。這使用到了一種設計模式 - 包裝類設計模式,大家可以先了解下這個模式更有利於理解,我也會把本篇實現的思路給出個思維導圖的。
看下效果圖吧:
首先來個bean物件,等下封裝資料使用:
public class Item {
private String maintitle;
private String subtitle;
public Item(String maintitle, String subtitle){
this .maintitle = maintitle;
this.subtitle = subtitle;
}
public String getMaintitle() {
return maintitle;
}
public String getSubtitle() {
return subtitle;
}
}
然後我們建立一個類WrapRecyclerView繼承自RecyclerView:
// 將recycle進行封裝
public class WrapRecyclerView extends RecyclerView {
private ArrayList<View> mHeadViewList = new ArrayList<View>();
private ArrayList<View> mFootViewList = new ArrayList<View>();
private Adapter mAdapter;
public WrapRecyclerView(Context context) {
super(context);
}
public WrapRecyclerView(Context context, AttributeSet attrs) {
super (context, attrs);
}
public WrapRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void addHeaderView(View view){
mHeadViewList.clear();
mHeadViewList.add(view);
if (mAdapter != null){
if (!(mAdapter instanceof RecylerWrapAdapter)){
mAdapter = new RecylerWrapAdapter(mHeadViewList,mFootViewList,mAdapter);
}
}
}
public void addFootView(View view){
mFootViewList.clear();
mFootViewList.add(view);
if (mAdapter != null){
if (!(mAdapter instanceof RecylerWrapAdapter)){
mAdapter = new RecylerWrapAdapter(mHeadViewList,mFootViewList,mAdapter);
}
}
}
@Override
public void setAdapter(Adapter adapter) {
if (mHeadViewList.isEmpty() && mFootViewList.isEmpty()){
super.setAdapter(adapter);
}else{
adapter = new RecylerWrapAdapter(mHeadViewList,mFootViewList,adapter);
super.setAdapter(adapter);
}
mAdapter = adapter;
}
}
//在佈局使用,使用系統的SwipeRefreshLayout包裹下
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/srl_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.wb.head.widget.WrapRecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v4.widget.SwipeRefreshLayout>
//然後在MainActivity的onCreate中獲取例項,進行初始化。還是我們上篇的那個MainActivity
recycler = (WrapRecyclerView) findViewById(R.id.recycler);
refresh = (SwipeRefreshLayout) findViewById(R.id.srl_refresh);
initRecycler();
initRefresh();
private void initRecycler(){
ll_headparent.removeView(rl_head);
recycler.addHeaderView(rl_head);
TextView textView = new TextView(this);
textView.setText("我是腳佈局");
textView.setBackgroundColor(getResources().getColor(R.color.colorAccent));
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,50);
textView.setGravity(Gravity.CENTER);
textView.setLayoutParams(params);
recycler.addFootView(textView);
mRecylerAdpater = new RecylerAdpater(loadData(0,6));
recycler.setAdapter(mRecylerAdpater);
recycler.setLayoutManager(new LinearLayoutManager(this));
recycler.setHasFixedSize(true);
onRecyclerClick();
}
// 如果連續快速點選,條目的動畫會有一個bug,所以使用了一個標記來禁止點選連續點選
boolean isClick = false;
private void onRecyclerClick(){
mRecylerAdpater.setOnItemClickLitener(new RecylerAdpater.OnItemClickLitener() {
@Override
public void onItemClick(View view, int position) {
if (!isClick){
isClick = true;
Toast.makeText(MainActivity.this, "點了我position" + position, Toast.LENGTH_SHORT).show();
ViewCompat.animate(view).setDuration(200).scaleX(0.9f).scaleY(0.9f).setInterpolator(new CycleInterpolator())
.setListener(new ViewPropertyAnimatorListener() {
@Override
public void onAnimationStart(View view) {}
@Override
public void onAnimationEnd(View view) {
isClick = false;
}
@Override
public void onAnimationCancel(View view) {}
}).withLayer().start();
}
}
@Override
public void onItemLongClick(View view, int position) {
Toast.makeText(MainActivity.this, "長按了我position" + position, Toast.LENGTH_SHORT).show();
}
});
}
private class CycleInterpolator implements android.view.animation.Interpolator {
private final float mCycles = 0.5f;
@Override
public float getInterpolation(final float input) {
return (float) Math.sin(2.0f * mCycles * Math.PI * input);
}
}
ArrayList<Item> items = new ArrayList<Item>();
private ArrayList loadData(int start,int end){
items.clear();
for (int i = start; i < end; i++) {
items.add(new Item("Item title :" + i,"This is the Item number :" + i));
}
return items;
}
// 模仿訪問網路,進行重新整理資料
private void initRefresh(){
refresh.setColorSchemeResources(android.R.color.holo_blue_light,
android.R.color.holo_red_light,android.R.color.holo_orange_light,
android.R.color.holo_green_light);
refresh.setProgressBackgroundColorSchemeColor(getResources().getColor(android.R.color.white));
refresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
items.clear();
mRecylerAdpater = new RecylerAdpater(loadData(10, 16));
recycler.setAdapter(mRecylerAdpater);
mRecylerAdpater.notifyDataSetChanged();
onRecyclerClick();
refresh.setRefreshing(false);
}
}, 4000);
}
});
}
然後我們在建立個類RecylerWrapAdapter繼承自RecyclerView.Adapter對adapter進行包裝:
public class RecylerWrapAdapter extends RecyclerView.Adapter{
private RecyclerView.Adapter mAdapter;
private ArrayList<View> mHeaderViews;
private ArrayList<View> mFootViews;
private final ArrayList<View> EMPTY_INFO_LIST = new ArrayList<View>();
private int mCurrentPosition;
public RecylerWrapAdapter(ArrayList<View> mHeaderViews,ArrayList<View> mFootViews,RecyclerView.Adapter mAdapter){
this.mAdapter = mAdapter;
if (mHeaderViews == null){
this.mHeaderViews = EMPTY_INFO_LIST;
}else{
this.mHeaderViews = mHeaderViews;
}
if (mFootViews == null){
this.mFootViews = EMPTY_INFO_LIST;
}else{
this.mFootViews = mFootViews;
}
}
public int getHeaderCount(){
return mHeaderViews.size();
}
public int getFootCount(){
return mFootViews.size();
}
/**
* 返回該position對應的item的id
* @param position
* @return
*/
@Override
public long getItemId(int position) {
int heads = getHeaderCount();
if (mAdapter != null && position >= heads){
int adjposition = position - heads; //減去頭佈局的當前位置
int adapterCount = mAdapter.getItemCount(); //總共有多少條目
if (adjposition < adapterCount){ // 當前位置如果是在條目中的
return mAdapter.getItemId(adjposition);
}
}
return -1;
}
@Override
public int getItemCount() {
if (mAdapter != null){
return getHeaderCount() + getFootCount() + mAdapter.getItemCount();
}else{
return getHeaderCount() +getFootCount();
}
}
/**
* 判斷應該返回的是頭佈局還是正常子佈局還是腳佈局 在onCreateViewHolder中使用
* @param position
* @return
*/
@Override
public int getItemViewType(int position) {
mCurrentPosition = position;
int heads = getHeaderCount();
// 也就是說recycle的第一個條目位置為頭佈局
if (position < heads){
// 返回型別為頭佈局
return RecyclerView.INVALID_TYPE;
}
int adjposition = position - heads; //減去頭佈局後當前佈局的位置
int adapterCount = 0;
if (mAdapter != null){
adapterCount = mAdapter.getItemCount();
if (adjposition < adapterCount){
//返回型別為正常佈局
return mAdapter.getItemViewType(adjposition);
}
}
// 返回型別為腳佈局
return RecyclerView.INVALID_TYPE - 1;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == RecyclerView.INVALID_TYPE){
// 返回頭佈局
return new HeaderViewHolder(mHeaderViews.get(0));
}else if (viewType == RecyclerView.INVALID_TYPE - 1){
// 返回腳佈局
return new HeaderViewHolder(mFootViews.get(0));
}
// 返回正常佈局
return mAdapter.onCreateViewHolder(parent,viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int heads = getHeaderCount();
if (position < heads) return;
int adjPosition = position - heads;
int adapterCount = 0;
if (mAdapter != null){
adapterCount = mAdapter.getItemCount();
if (adjPosition < adapterCount){
// 繫結正常條目資料
mAdapter.onBindViewHolder(holder,adjPosition);
return;
}
}
}
private class HeaderViewHolder extends RecyclerView.ViewHolder{
public HeaderViewHolder(View itemView) {
super(itemView);
}
}
}
現在包裝類寫完了,但我們的RecyclerView還沒有Adapter的,那我們就建立吧,和使用普通RecyclerView的Adapter一樣:
public class RecylerAdpater extends RecyclerView.Adapter<RecylerAdpater.MyViewHolder> {
private List items;
public RecylerAdpater(List list){
super();
items = list;
}
@Override
public int getItemCount() {
return items.size();
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false);
return new MyViewHolder(v);
}
@Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
Item item = (Item)items.get(position);
holder.mTitle.setText(item.getMaintitle());
holder.mSubtitle.setText(item.getSubtitle());
if (mOnItemClickLitener != null){
// 設定點選事件 通過系統view類的回撥設定我們的回撥
holder.ll_item.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemClick(holder.ll_item,pos);
}
});
// 設定長按事件 通過系統view類的回撥設定我們的回撥
holder.ll_item.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
int pos = holder.getLayoutPosition();
mOnItemClickLitener.onItemLongClick(holder.ll_item,pos);
return true;
}
});
}
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView mTitle;
TextView mSubtitle;
LinearLayout ll_item;
public MyViewHolder(View itemView) {
super(itemView);
mTitle = (TextView) itemView.findViewById(R.id.maintitle);
mSubtitle = (TextView) itemView.findViewById(R.id.subtitle);
ll_item = (LinearLayout) itemView.findViewById(R.id.ll_item);
}
}
//回撥介面用於點選事件
public interface OnItemClickLitener{
void onItemClick(View view,int position);
void onItemLongClick(View view,int position);
}
private OnItemClickLitener mOnItemClickLitener;
public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener){
this.mOnItemClickLitener = mOnItemClickLitener;
}
}
OK,現在大功告成,我們已經在MainActivity的initRecycler()方法中使用了,執行就可以看到效果了。
對包裝類設計模式不熟悉的朋友可能會有些疑問,下面給大家貼出我做的思維導圖:
最好的方法還是自己寫出來,斷點下就清楚這個設計模式和執行流程了。如有哪裡不足,歡迎指教。