国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

仿新浪個人信息頁布局

2019-11-06 09:53:24
字體:
來源:轉載
供稿:網友

?最近項目中需要一個類似微博個人信息頁的布局,網上找了一些資料但都不符合自己的需求,故自己實現一個。

一.模仿布局樣式原型:

這里寫圖片描述

?上圖是新浪微博個人信息頁的整體布局,可以看到整個布局是一個可以滾動列表結構,上邊是一個個人信息布局和一個tab選擇欄布局,看到這個布局之后我們可以想到用scrollview+listview來完成,但由于使用這種嵌套方式之后需重寫listview高度而導致item無法復用,故我們使用另一種方式來完成,也就是RecyclerView充當整個布局的方式,個人信息布局和tab選擇欄作為header插入到列表中。 ?下邊來讓我們思考一下即將實現布局將會遇到的問題: ?1.RecyclerView如何加header和footer進去? ?2.怎樣做到懸浮tab欄效果? ?3.怎么在同一個列表中加載不同的樣式? ?4.如何在點tab欄切換數據的時候保持列表處于上一次的位置?

問題一:RecyclerView如何加header和footer進去?

? 我們都知道RecylerView不像Listview一樣有addheaderview和addfooterview兩個方法,既然沒有這兩個方法我們就需要自己去寫這兩個方法并且去實現了,我們知道RecyclerView的adapter中有一個叫getItemViewType(int position)的方法,我們可以通過重寫這個方法來讓RecyclerView的item根據條件不同加載不同種類的布局,那我們便可以通過重寫這個方法將header和footer作為item項加入到RecyclerView中從而達到加header和footer的效果。適配器的代碼如下:

package com.ifeng.art.common.widget.recyclerview;import android.content.Context;import android.support.v4.util.SparseArrayCompat;import android.support.v7.widget.GridLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;import android.view.ViewGroup;import java.util.ArrayList;import java.util.List;/** * Created by lvzishen on 16/10/8. */public abstract class WrapperRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { PRotected List list = new ArrayList<>(); protected Context context;// /**// * 頭布局// */// private View headView;// /**// * 頭布局Tab// */// private View headViewTab; /** * 頭布局 * key: Integer; value: object */ private SparseArrayCompat<View> mHeaderViews = new SparseArrayCompat<>(); /** * 頭布局Tab */ private View headViewTab; /** * 腳布局 */ private FooterView footView;// /**// * 頭布局數量// */// public int headViewCount = 0; /** * 腳布局數量 */ public int footViewCount = 0; public int getFootViewCount() { return footViewCount; } private static final int TYPE_HEADER = 1; private static final int TYPE_FOOTER = 3; private FootViewHolder footViewHolder; public void setList(List listData) { this.list.clear(); this.list.addAll(listData); this.notifyDataSetChanged(); } public WrapperRecyclerAdapter(Context context) { this.context = context; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (mHeaderViews.get(viewType) != null) { return new HeadViewHolder(mHeaderViews.get(viewType)); } else if (viewType == TYPE_FOOTER) { return footViewHolder; } else { return onCreateViewHolderNormal(parent, viewType); } } public abstract RecyclerView.ViewHolder onCreateViewHolderNormal(ViewGroup parent, int viewType); @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { position = getRealPosition(position); onBindViewHolderNormal(holder, position); } public abstract void onBindViewHolderNormal(RecyclerView.ViewHolder holder, int position); @Override public int getItemCount() { return list.size() + mHeaderViews.size() + footViewCount; } public void addHeaderView(View head) { this.mHeaderViews.put(mHeaderViews.size() + TYPE_HEADER, head); notifyItemInserted(mHeaderViews.size() - 1); } public void addFooterView(FooterView footView) { this.footView = footView; footViewCount++; footViewHolder = new FootViewHolder(footView); notifyItemInserted(getItemCount() - 1); } public void removeFooterView() { if (footView != null) { footViewCount = 0; footViewHolder = null; footView = null; notifyItemRemoved(getItemCount() - 1); } } public void removeHeaderView() { if (mHeaderViews.size() > 0) {// headViewCount = 0; mHeaderViews.clear(); for (int i = 0; i < mHeaderViews.size(); i++) { notifyItemRemoved(i); } } } @Override public int getItemViewType(int position) { if (position < mHeaderViews.size()) { return mHeaderViews.keyAt(position); } if (position == getItemCount() - 1 && footView != null) { //最后一個,應該加載Footer return TYPE_FOOTER; } return getItemViewTypeNormal(getRealPosition(position)); } public abstract int getItemViewTypeNormal(int position); /** * 得到真實的position * * @return */ private int getRealPosition(int position) { return position = position - mHeaderViews.size(); } public void setState(int status) { if (footViewHolder != null) { footView.setState(status); } } /** * @param errorListener 腳布局加載失敗 */ public void setErrorListener(FooterView.ErrorListener errorListener) { footView.setOnErrorListener(errorListener); } @Override public void onAttachedToRecyclerView(RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager; gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { int spanSize = 1; //每個griditem 占1份 一行有3個網格item 每個spansize為1 一個item占滿則需要返回3 if (position == 0 && mHeaderViews != null && mHeaderViews.size() > 0) { return gridLayoutManager.getSpanCount(); } if (position == getItemCount() - 1 && footView != null && footViewCount > 0) { return gridLayoutManager.getSpanCount(); } return spanSize; } }); } } public int getState() { if (footView != null) { return footView.getStatus(); } return 0; } class HeadViewHolder extends RecyclerView.ViewHolder { public HeadViewHolder(View itemView) { super(itemView); } } class FootViewHolder extends RecyclerView.ViewHolder { public FootViewHolder(View itemView) { super(itemView); } }}

? 這里講的不是很詳細,只是給了大家思路并且簡單的實現了一下效果,因為網上已經有很多關于這方面的資料了,如果有不明白的地方可以評論留言給我或者自行查閱資料。這個adapter中我還加入了一些關于footer狀態的地方,是因為我們要控制footer去根據不同的狀態加載不同的布局類型,具體可以看最后的demo代碼。

問題二:怎樣做到懸浮tab欄效果?

? 可以看到當我們向上拖動列表的時候會出現一個跟頭布局相同的tab懸浮欄懸浮在最上方。這里我們采用一個簡單的方法,RecyclerView中可以通過設置 RecyclerView.OnScrollListener這個接口去監聽到RecyclerView的滾動狀態,第一個顯示的item,總共顯示的item個數等等,我們可以利用這個抽象類去達到效果。 ? 具體的思路為在RecyclerView的根布局中加一個和headview tab欄中布局相同的tab,并且隱藏這個tab。當我們滾動列表時,第一個可見的item為headview tab的位置的時候(此布局position為1)我們就將隱藏的tab顯示出來從而給用戶造成一個tab懸浮在最上層的假象。因為我們這個隱藏顯示的tab和headview中的tab并不是同一個tab,所以當我們改變其中一個tab的狀態的時候要對應的改變另一個tab,這樣才能讓數據同步。下邊給出OnScrollListener的代碼:

package com.ifeng.art.common.widget.recyclerview;import android.support.v7.widget.GridLayoutManager;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.util.Log;/** * Created by lvzishen on 16/10/9. */public abstract class RecyclerViewLoadData extends RecyclerView.OnScrollListener { private RecyclerView.LayoutManager layoutManager; private int lastVisibleItem; private int firstVisbleItem; private int totalItemCount; private int visibleItemCount; public RecyclerViewLoadData(RecyclerView.LayoutManager layoutManager) { this.layoutManager = layoutManager; } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); // 獲取到最后一個可見的item if (layoutManager instanceof LinearLayoutManager) { lastVisibleItem = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition(); //得到當前顯示的第一個item的位置 firstVisbleItem = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition(); //如果第一個可見的item為大于等于1則顯示懸浮tab if (firstVisbleItem >= 1) { showTab(); } else { hideTab(); } getFirstVisiblePosition(firstVisbleItem); } if (layoutManager instanceof GridLayoutManager) { lastVisibleItem = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition(); } } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); // 獲取item的總數 totalItemCount = layoutManager.getItemCount(); //可見的item數 visibleItemCount = layoutManager.getChildCount();// Log.e("totalItemCount", totalItemCount + "");// Log.e("visibleItemCount", visibleItemCount + ""); if (newState == RecyclerView.SCROLL_STATE_IDLE && lastVisibleItem >= totalItemCount - 1 && visibleItemCount > 0) { // 此處調用加載更多回調接口的回調方法 int state = RecyclerViewStateUtils.getFooterViewState(recyclerView); if (state == FooterView.Loading || state == FooterView.TheEnd) { Log.d("state not allow", "the state is Loading/The End, just wait.."); return; } loadMoreData(recyclerView); } } public abstract void loadMoreData(RecyclerView recyclerView); public abstract void getFirstVisiblePosition(int firstVisiblePosition); public abstract void showTab(); public abstract void hideTab();}

問題三:怎么在同一個列表中加載不同的樣式?

? 這個問題的答案和我們第一個加headview和footview的思路相同,再次不再多說,要注意adapter中并不是只能加載一種類型的數據,我們可以根據加載的數據類型不同加載不同類型的布局從而達到像微博列表中那樣的一個列表是正常的列表布局(多個list集合,根據tab的切換讓adapter加載不同的list集合),一個列表是網格形布局的情況,其實只不過是加載了不同的布局(第一種是加載正常布局item,第二種是加載三個imageview并排的item),下邊給出適配器的代碼:

package com.ifeng.art.adapter;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import android.widget.TextView;import com.ifeng.art.R;import com.ifeng.art.common.widget.recyclerview.WrapperRecyclerAdapter;import com.ifeng.art.entity.UserNickname;import com.ifeng.art.entity.UserNumber;/** * Created by lvzishen on 16/11/2. */public class DemoWrapperRecyclerAdapter extends WrapperRecyclerAdapter { private final int TYPE_ONE = 10; private final int TYPE_TWO = 11; public DemoWrapperRecyclerAdapter(Context context) { super(context); } @Override public RecyclerView.ViewHolder onCreateViewHolderNormal(ViewGroup parent, int viewType) { if (viewType == TYPE_ONE) { View view = LayoutInflater.from(context).inflate(R.layout.item_normal, parent, false); return new NormalHolder(view); } if (viewType == TYPE_TWO) { View view2 = LayoutInflater.from(context).inflate(R.layout.item_normal_two, parent, false); return new NormalHolder2(view2); } return null; } @Override public void onBindViewHolderNormal(RecyclerView.ViewHolder holder, final int position) { if (holder instanceof NormalHolder) { final UserNumber art = (UserNumber) list.get(position); ((NormalHolder) holder).textView.setText(art.follows); ((NormalHolder) holder).textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e("position", position + ""); } }); } if (holder instanceof NormalHolder2) { final UserNickname huodong = (UserNickname) list.get(position); ((NormalHolder2) holder).textView.setText(huodong.uname);// Glide.with(context)// .load(huodong.image)// .placeholder(R.color.default_image)// .into(((NormalHolder2) holder).imageView); ((NormalHolder2) holder).textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.e("position", position + ""); } }); } } @Override public int getItemViewTypeNormal(int position) { if (list.get(position) instanceof UserNickname) { return TYPE_TWO; } else { return TYPE_ONE; } } class NormalHolder extends RecyclerView.ViewHolder { TextView textView; public NormalHolder(View itemView) { super(itemView); textView = (TextView) itemView.findViewById(R.id.item_textview); } } class NormalHolder2 extends RecyclerView.ViewHolder { TextView textView; ImageView imageView; public NormalHolder2(View itemView) { super(itemView); textView = (TextView) itemView.findViewById(R.id.item_textview); imageView = (ImageView) itemView.findViewById(R.id.image); } }}

問題四:如何在點tab欄切換數據的時候保持列表處于上一次的位置?

? 當我們點擊tab欄切換不同的集合時需要保持列表處于上一次顯示的位置,我們可以獲取到第一個可見的item位置并且記錄下來,然后使用scrollToPositionWithOffset(int position, int offset)這個方法來讓RecyclerView去切換到指定的位置上,其中的邏輯判斷比較繁瑣,具體的邏輯可以看最后demo中的代碼。

最后讓我們看一下實現出來的效果

這里寫圖片描述

最后給出代碼地址 https://github.com/lvzishen/WeiboTabDemo


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 吉安市| 同仁县| 鄢陵县| 金秀| 尼勒克县| 双江| 平江县| 桑日县| 诏安县| 锡林郭勒盟| 革吉县| 桑日县| 博湖县| 屏山县| 邵东县| 岑巩县| 胶南市| 郴州市| 余干县| 白玉县| 永顺县| 曲阳县| 新营市| 怀安县| 茶陵县| 江阴市| 龙门县| 扎兰屯市| 嘉定区| 修文县| 昭苏县| 公安县| 遵化市| 荃湾区| 曲周县| 弋阳县| 镇远县| 紫云| 通山县| 大田县| 个旧市|