先看一下效果圖:

左邊就是一個普通的recyclerView,右邊則需要一個有標(biāo)題的recyclerView。
sticky-headers-recyclerview
項目地址:https://github.com/timehop/sticky-headers-recyclerview
用它在寫adapter的時候,記得寫兩個viewholder,一個content,一個header的。
其中根據(jù)getHeaderId(int position)來確定標(biāo)題,返回值相同的屬于同一個標(biāo)題。
添加標(biāo)題
// Add the sticky headers decoration,給球隊添加標(biāo)題
final StickyRecyclerHeadersDecoration headersDecor = new StickyRecyclerHeadersDecoration(teamsAndHeaderAdapter);
recyclerviewTeams.addItemDecoration(headersDecor);
只多了這一步操作,就給recyclerView相同分類的item加上標(biāo)題了。
adapter
/**
* Created by chenlijin on 2016/3/18.
*/
public class TeamsAndHeaderAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements StickyRecyclerHeadersAdapter<RecyclerView.ViewHolder> {
private List<Category> categoryList;
private List<Team> teamList = new ArrayList<>();
private Context mContext;
public TeamsAndHeaderAdapter(Context context,List<Category> categoryList) {
mContext = context;
setCategoryList(categoryList);
}
public void setCategoryList(List<Category> categoryList) {
this.categoryList = categoryList;
for(int i = 0;i<categoryList.size();i++){
if(teamList!=null){
teamList.addAll(categoryList.get(i).getTeamList());
}
}
notifyDataSetChanged();
}
public List<Category> getCategoryList() {
return categoryList;
}
@Override
public int getItemCount() {
return teamList.size();
}
/**
* 返回值相同會被默認為同一項
* @param position
* @return
*/
@Override
public long getHeaderId(int position) {
return getSortType(position);
}
//獲取當(dāng)前球隊的類型
public int getSortType(int position) {
int sort = -1;
int sum = 0;
for (int i=0;i<categoryList.size();i++){
if(position>=sum){
sort++;
}else {
return sort;
}
sum += categoryList.get(i).getTeamList().size();
}
return sort;
}
/**
* =========================================================================
* header的ViewHolder
* ========================================================================
*/
@Override
public ContentViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_team, parent, false);
return new ContentViewHolder(view);
}
@Override
public void onBindHeaderViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
TextView textView = (TextView) viewHolder.itemView;
textView.setText(categoryList.get(getSortType(position)).getSortName());
textView.setBackgroundColor(getRandomColor());
}
private class HeaderViewHolder extends RecyclerView.ViewHolder {
public HeaderViewHolder(View itemView) {
super(itemView);
}
}
private int getRandomColor() {
SecureRandom rgen = new SecureRandom();
return Color.HSVToColor(150, new float[]{
rgen.nextInt(359), 1, 1
});
}
/**
* =========================================================================
* 以下為contentViewHolder
* =========================================================================
*/
@Override
public ContentViewHolder onCreateHeaderViewHolder(ViewGroup viewGroup) {
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.header_team_list, viewGroup, false);
return new ContentViewHolder(view);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
ContentViewHolder viewHolder = (ContentViewHolder) holder;
viewHolder.textView.setText(teamList.get(position).getName());
//glide谷歌推薦的圖片加載庫
Glide.with(mContext)
.load(teamList.get(position).getImagePath())
.placeholder(R.drawable.icon_logo_image_default)
.centerCrop()
.into(viewHolder.imageViewTeam);
}
private class ContentViewHolder extends RecyclerView.ViewHolder {
TextView textView;
ImageView imageViewTeam;
public ContentViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.textview_teamname);
imageViewTeam = (ImageView) itemView.findViewById(R.id.imageview_team);
}
}
}
兩個recyclerView的相互監(jiān)聽
右邊滾動,左邊切換
監(jiān)聽滾動OnScrollChangeListener,由layoutmanager獲取到第一個完全顯示的item的position。再進行判斷:
recyclerviewTeams.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
//第一個完全顯示的item和最后一個item。
int firstVisibleItem = mTeamsLayoutManager.findFirstCompletelyVisibleItemPosition();
int lastVisibleItem = mTeamsLayoutManager.findLastVisibleItemPosition();
//此判斷,避免左側(cè)點擊最后一個item無響應(yīng)
if(lastVisibleItem != mTeamsLayoutManager.getItemCount()-1){
int sort = teamsAndHeaderAdapter.getSortType(firstVisibleItem);
changeSelected(sort);
}else {
changeSelected(categoryAdapter.getItemCount()-1);
}
if(needMove){
needMove = false;
//獲取要置頂?shù)捻椩诋?dāng)前屏幕的位置,mIndex是記錄的要置頂項在RecyclerView中的位置
int n = movePosition - mTeamsLayoutManager.findFirstVisibleItemPosition();
if ( 0 <= n && n < recyclerviewTeams.getChildCount()){
//獲取要置頂?shù)捻楉敳侩xRecyclerView頂部的距離
int top = recyclerviewTeams.getChildAt(n).getTop()-dip2px(MainActivity.this,28);
//最后的移動
recyclerviewTeams.scrollBy(0, top);
}
}
}
});
左邊點擊,右邊滾動到相應(yīng)位置
recyclerView有三種滾動的方法:scrollTo,scrollBy,scrollToPosition。
scrollTo這個方法無響應(yīng),至于這個方法是做什么的?還請賜教。。。
scrollToPosition這個方法比較神奇。它分三種情況:
1,position在界面內(nèi),無反應(yīng)
2,position在界面下方,則滾動此position到底部。
3,position在界面上方,則滾動此position到頂部。
scrollBy這個是最靠譜的一個方法了,從當(dāng)前位置相對進行位移,可正可負。
按理說scrollBy是最簡單的,但是recyclerviewTeams.getChildAt(n - firstItem),item如果不在屏幕內(nèi)就會為空,所以就需要先把item移到屏幕內(nèi)。。。這樣如果item在屏幕下方,就需要先scrollToPosition,再scrollBy。所以要監(jiān)聽滾動,item在屏幕下方時,第一次滾動完成后,進行第二次滾動。
private void moveToPosition(int n) {
//先從RecyclerView的LayoutManager中獲取第一項和最后一項的Position
int firstItem = mTeamsLayoutManager.findFirstVisibleItemPosition();
int lastItem = mTeamsLayoutManager.findLastVisibleItemPosition();
//然后區(qū)分情況
if (n <= firstItem ){
//當(dāng)要置頂?shù)捻椩诋?dāng)前顯示的第一個項的前面時
recyclerviewTeams.scrollToPosition(n);
}else if ( n <= lastItem ){
//當(dāng)要置頂?shù)捻椧呀?jīng)在屏幕上顯示時
int top = recyclerviewTeams.getChildAt(n - firstItem).getTop();
recyclerviewTeams.scrollBy(0, top-dip2px(this,28));
}else{
//當(dāng)要置頂?shù)捻椩诋?dāng)前顯示的最后一項的后面時
recyclerviewTeams.scrollToPosition(n);
movePosition = n;
needMove = true;
}
}
item在屏幕下方時,在監(jiān)聽里添加
if(needMove){
needMove = false;
//獲取要置頂?shù)捻椩诋?dāng)前屏幕的位置,mIndex是記錄的要置頂項在RecyclerView中的位置
int n = movePosition - mTeamsLayoutManager.findFirstVisibleItemPosition();
if ( 0 <= n && n < recyclerviewTeams.getChildCount()){
//獲取要置頂?shù)捻楉敳侩xRecyclerView頂部的距離
int top = recyclerviewTeams.getChildAt(n).getTop()-dip2px(MainActivity.this,28);
//最后的移動
recyclerviewTeams.scrollBy(0, top);
}
}
到此,左右兩端的相互關(guān)聯(lián)就完成了。