189 8069 5689

Android怎么实现Recycleview悬浮粘性头部外加右侧字母导航

这篇文章将为大家详细讲解有关Android怎么实现Recycleview悬浮粘性头部外加右侧字母导航,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

网站建设公司,为您提供网站建设,网站制作,网页设计及定制网站建设服务,专注于成都企业网站建设,高端网页制作,对成都边坡防护网等多个行业拥有丰富的网站建设经验的网站建设公司。专业网站设计,网站优化推广哪家好,专业seo优化优化,H5建站,响应式网站。

公司项目要实现这个效果:Android实现Recycleview悬浮粘性头部外加右侧字母导航

Android怎么实现Recycleview悬浮粘性头部外加右侧字母导航

Android怎么实现Recycleview悬浮粘性头部外加右侧字母导航

图一是开始的画面,图二是滑动的画面,点击右侧字母需要滑动左侧到指定位置,然后左侧的顶部字母A,B等需要悬浮。

实现思路:

右侧的联动可以用recycyeview中adapter的scrollToPositionWithOffset方法实现。左侧就是recycleview,后台返回的城市数据是这种类型的:

复制代码 代码如下:

{"returnCode":1,"returnMsg":"操作成功","data":[{"startWord":"A","trainCityList":[{"cityId":531,"cityName":"昂昂溪","code":null},{"cityId":2137,


我进行了一层封装

1.建立实体类用来封装下标和城市名字:

public class ContactModel {
 private String index;
 private String name;

 public ContactModel(String name){
  this.index = NewFirstLetterUtil.getFirstLetter(name);
  this.name = name;
 }

 public String getIndex() {
  return index;
 }

 public String getName() {
  return name;
 }
 
}

2.讲服务器返回的数据进行封装:

 List contacts = new ArrayList<>();
   for (int i=0;i

3.设置适配器

private void setNewAdapter() {

   ContactsAdapter mAdapter = new ContactsAdapter(mShowModels);
   mMainRecycleview.setLayoutManager(new LinearLayoutManager(this));
   final StickyRecyclerHeadersDecoration headersDecor = new StickyRecyclerHeadersDecoration(mAdapter);
   mMainRecycleview.addItemDecoration(headersDecor);

   mAdapter.setOnItemClickListtener(new ContactsAdapter.OnItemClickListtener() {
    @Override
    public void onItemClick(int pos) {
     // Toast.makeText(TrainNewStartActivity.this,"惦记的pos:"+pos+"数据:"+mShowModels.get(pos).getName(),Toast.LENGTH_SHORT).show();
     Intent intent = new Intent();
     intent.putExtra("data", mShowModels.get(pos).getName());
     Log.d("lwp","data:"+mShowModels.get(pos).getName());
     setResult(RESULT_OK, intent);
     finish();
    }
   });
   mMainRecycleview.setAdapter(mAdapter);
   mMain_side_bar.setLazyRespond(false);
   // 侧边设置相关
   mMain_side_bar.setOnSelectIndexItemListener(new WaveSideBarView.OnSelectIndexItemListener() {
    @Override
    public void onSelectIndexItem(String letter) {
     for (int i = 0; i< mContactModels.size(); i++) {
      if (mContactModels.get(i).getIndex().equals(letter)) {
       ((LinearLayoutManager) mMainRecycleview.getLayoutManager()).scrollToPositionWithOffset(i, 0);
       return;
      }
     }
    }
   });
}

4.适配器代码:

public class ContactsAdapter extends RecyclerView.Adapter implements StickyRecyclerHeadersAdapter {

 private List contacts;
 private static final String TAG = "ContactsAdapter";
 private ContactModel contact;

 public ContactsAdapter(List contacts) {
  this.contacts = contacts;
 }

 @Override
 public ContactsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
  LayoutInflater inflater = LayoutInflater.from(parent.getContext());
  View view = inflater.inflate(R.layout.layaout_item_contacts, null);
  return new ContactsViewHolder(view);
 }

 @Override
 public void onBindViewHolder(ContactsViewHolder holder, final int position) {
  contact = contacts.get(position);
  Log.e(TAG, "onBindViewHolder: index:" + contact.getIndex());
  if (position == 0 || !contacts.get(position-1).getIndex().equals(contact.getIndex())) {
   holder.tvIndex.setVisibility(View.GONE);
   holder.tvIndex.setText(contact.getIndex());
  } else {
   holder.tvIndex.setVisibility(View.GONE);
  }
  holder.tvName.setText(contact.getName());
  holder.tvName.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    Log.d("lwp","惦记的pos:"+position);
    onItemClickListtener.onItemClick(position);
   }
  });
 }

 public interface OnItemClickListtener{
  void onItemClick(int pos);
 }

 public OnItemClickListtener onItemClickListtener;

 public void setOnItemClickListtener(OnItemClickListtener onItemClickListtener) {
  this.onItemClickListtener = onItemClickListtener;
 }

 @Override
 public long getHeaderId(int position) {
  if (contacts.get(position).getIndex().equals("A")){
   return 0;
  }else if (contacts.get(position).getIndex().equals("B")){
   return 1;
  }else if (contacts.get(position).getIndex().equals("C")){
   return 2;
  }else if (contacts.get(position).getIndex().equals("D")){
   return 3;
  }else if (contacts.get(position).getIndex().equals("E")){
   return 4;
  }else if (contacts.get(position).getIndex().equals("F")){
   return 5;
  }else if (contacts.get(position).getIndex().equals("G")){
   return 6;
  }else if (contacts.get(position).getIndex().equals("H")){
   return 7;
  }else if (contacts.get(position).getIndex().equals("I")){
   return 8;
  }else if (contacts.get(position).getIndex().equals("J")){
   return 9;
  }else if (contacts.get(position).getIndex().equals("K")){
   return 10;
  }else if (contacts.get(position).getIndex().equals("L")){
   return 11;
  }else if (contacts.get(position).getIndex().equals("M")){
   return 12;
  }else if (contacts.get(position).getIndex().equals("N")){
   return 13;
  }else if (contacts.get(position).getIndex().equals("O")){
   return 14;
  }else if (contacts.get(position).getIndex().equals("P")){
   return 15;
  }else if (contacts.get(position).getIndex().equals("Q")){
   return 16;
  }else if (contacts.get(position).getIndex().equals("R")){
   return 17;
  }else if (contacts.get(position).getIndex().equals("S")){
   return 18;
  }else if (contacts.get(position).getIndex().equals("T")){
   return 19;
  }else if (contacts.get(position).getIndex().equals("U")){
   return 20;
  }else if (contacts.get(position).getIndex().equals("V")){
   return 21;
  }else if (contacts.get(position).getIndex().equals("Y")){
   return 22;
  }else if (contacts.get(position).getIndex().equals("X")){
   return 23;
  }else if (contacts.get(position).getIndex().equals("Y")){
   return 24;
  }else if (contacts.get(position).getIndex().equals("Z")){
   return 25;
  }else {
   return -1;
  }

 }

 @Override
 public RecyclerView.ViewHolder onCreateHeaderViewHolder(ViewGroup parent) {
  View view = LayoutInflater.from(parent.getContext())
    .inflate(R.layout.view_header, parent, false);
  return new RecyclerView.ViewHolder(view) {
  };
 }

 @Override
 public void onBindHeaderViewHolder(RecyclerView.ViewHolder holder, int position) {
  TextView textView = (TextView) holder.itemView;
  textView.setText(String.valueOf(contacts.get(position).getIndex()));
 }

 @Override
 public int getItemCount() {
  return contacts.size();
 }

 class ContactsViewHolder extends RecyclerView.ViewHolder {
  TextView tvIndex;
  ImageView ivAvatar;
  TextView tvName;

  ContactsViewHolder(View itemView) {
   super(itemView);
   tvIndex = (TextView) itemView.findViewById(R.id.tv_index);
   ivAvatar = (ImageView) itemView.findViewById(R.id.iv_avatar);
   tvName = (TextView) itemView.findViewById(R.id.tv_name);
  }
 }
}

5.两个布局文件:

layaout_item_contacts.xml:




 

 
  

  
 

 

view_header.xml:



采用的第三方:

compile 'com.github.nanchen2251:WaveSideBar:1.0.6'
compile 'com.timehop.stickyheadersrecyclerview:library:0.4.3@aar'

右侧字母用的是wavesidebar,但是由于不太符合设计图,所有我没有用他的,而是自己拿过来重新定义了(该类没提供修改,建议完善),如下:

public class SlfWaveSlideBarView extends View {
 private final static int DEFAULT_TEXT_SIZE = 14; // sp
 private final static int DEFAULT_MAX_OFFSET = 80; //dp

 private final static String[] DEFAULT_INDEX_ITEMS = {"A", "B", "C", "D", "E", "F", "G", "H", "I",
   "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};

 private String[] mIndexItems;

 /**
  * the index in {@link #mIndexItems} of the current selected index item,
  * it's reset to -1 when the finger up
  */
 private int mCurrentIndex = -1;

 /**
  * Y coordinate of the point where finger is touching,
  * the baseline is top of {@link #mStartTouchingArea}
  * it's reset to -1 when the finger up
  */
 private float mCurrentY = -1;

 private Paint mPaint;
 private int mTextColor;
 private float mTextSize;

 /**
  * the height of each index item
  */
 private float mIndexItemHeight;

 /**
  * offset of the current selected index item
  */
 private float mMaxOffset;

 /**
  * {@link #mStartTouching} will be set to true when {@link MotionEvent#ACTION_DOWN}
  * happens in this area, and the side bar should start working.
  */
 private RectF mStartTouchingArea = new RectF();

 /**
  * height and width of {@link #mStartTouchingArea}
  */
 private float mBarHeight;
 private float mBarWidth;

 /**
  * Flag that the finger is starting touching.
  * If true, it means the {@link MotionEvent#ACTION_DOWN} happened but
  * {@link MotionEvent#ACTION_UP} not yet.
  */
 private boolean mStartTouching = false;

 /**
  * if true, the {@link WaveSideBarView.OnSelectIndexItemListener#onSelectIndexItem(String)}
  * will not be called until the finger up.
  * if false, it will be called when the finger down, up and move.
  */
 private boolean mLazyRespond = false;

 /**
  * the position of the side bar, default is {@link #POSITION_RIGHT}.
  * You can set it to {@link #POSITION_LEFT} for people who use phone with left hand.
  */
 private int mSideBarPosition;
 public static final int POSITION_RIGHT = 0;
 public static final int POSITION_LEFT = 1;

 /**
  * the alignment of items, default is {@link #TEXT_ALIGN_CENTER}.
  */
 private int mTextAlignment;
 public static final int TEXT_ALIGN_CENTER = 0;
 public static final int TEXT_ALIGN_LEFT = 1;
 public static final int TEXT_ALIGN_RIGHT = 2;


 /**
  * observe the current selected index item
  */
 private WaveSideBarView.OnSelectIndexItemListener onSelectIndexItemListener;

 /**
  * the baseline of the first index item text to draw
  */
 private float mFirstItemBaseLineY;

 /**
  * for {@link #dp2px(int)} and {@link #sp2px(int)}
  */
 private DisplayMetrics mDisplayMetrics;


 public SlfWaveSlideBarView(Context context) {
  this(context, null);
 }

 public SlfWaveSlideBarView(Context context, AttributeSet attrs) {
  this(context, attrs, 0);
 }

 public SlfWaveSlideBarView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  mDisplayMetrics = context.getResources().getDisplayMetrics();

  TypedArray typedArray = context.obtainStyledAttributes(attrs, com.nanchen.wavesidebar.R.styleable.WaveSideBarView);
  mLazyRespond = typedArray.getBoolean(com.nanchen.wavesidebar.R.styleable.WaveSideBarView_sidebar_lazy_respond, false);
  mTextColor = typedArray.getColor(com.nanchen.wavesidebar.R.styleable.WaveSideBarView_sidebar_text_color, Color.GRAY);
  mMaxOffset = typedArray.getDimension(com.nanchen.wavesidebar.R.styleable.WaveSideBarView_sidebar_max_offset, dp2px(DEFAULT_MAX_OFFSET));
  mSideBarPosition = typedArray.getInt(com.nanchen.wavesidebar.R.styleable.WaveSideBarView_sidebar_position, POSITION_RIGHT);
  mTextAlignment = typedArray.getInt(com.nanchen.wavesidebar.R.styleable.WaveSideBarView_sidebar_text_alignment, TEXT_ALIGN_CENTER);
  typedArray.recycle();

  mTextSize = sp2px(DEFAULT_TEXT_SIZE);

  mIndexItems = DEFAULT_INDEX_ITEMS;

  initPaint();
 }

 private void initPaint() {
  mPaint = new Paint();
  mPaint.setAntiAlias(true);
  mPaint.setColor(mTextColor);
  mPaint.setTextSize(mTextSize);
  switch (mTextAlignment) {
   case TEXT_ALIGN_CENTER: mPaint.setTextAlign(Paint.Align.CENTER); break;
   case TEXT_ALIGN_LEFT: mPaint.setTextAlign(Paint.Align.LEFT); break;
   case TEXT_ALIGN_RIGHT: mPaint.setTextAlign(Paint.Align.RIGHT); break;
  }
 }

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);

  int height = MeasureSpec.getSize(heightMeasureSpec);
  int width = MeasureSpec.getSize(widthMeasureSpec);

  Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
  mIndexItemHeight = fontMetrics.bottom - fontMetrics.top;
  mBarHeight = mIndexItems.length * mIndexItemHeight;

  // calculate the width of the longest text as the width of side bar
  for (String indexItem : mIndexItems) {
   mBarWidth = Math.max(mBarWidth, mPaint.measureText(indexItem));
  }

  float areaLeft = (mSideBarPosition == POSITION_LEFT) ? 0 : (width - mBarWidth - getPaddingRight());
  float areaRight = (mSideBarPosition == POSITION_LEFT) ? (getPaddingLeft() + areaLeft + mBarWidth) : width;
  float areaTop = height/2 - mBarHeight/2;
  float areaBottom = areaTop + mBarHeight;
  mStartTouchingArea.set(
    areaLeft,
    areaTop,
    areaRight,
    areaBottom);

  // the baseline Y of the first item' text to draw
  mFirstItemBaseLineY = (height/2 - mIndexItems.length*mIndexItemHeight/2)
    + (mIndexItemHeight/2 - (fontMetrics.descent-fontMetrics.ascent)/2)
    - fontMetrics.ascent;
 }

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);

  // draw each item
  for (int i = 0, mIndexItemsLength = mIndexItems.length; i < mIndexItemsLength; i++) {
   float baseLineY = mFirstItemBaseLineY + mIndexItemHeight*i;

   // calculate the scale factor of the item to draw
   float scale = getItemScale(i);

   int alphaScale = (i == mCurrentIndex) ? (255) : (int) (255 * (1-scale));
   mPaint.setAlpha(alphaScale);

   mPaint.setTextSize(mTextSize + mTextSize*scale);

   float baseLineX = 0f;
   if (mSideBarPosition == POSITION_LEFT) {
    switch (mTextAlignment) {
     case TEXT_ALIGN_CENTER:
      baseLineX = getPaddingLeft() + mBarWidth/2 + mMaxOffset*scale;
      break;
     case TEXT_ALIGN_LEFT:
      baseLineX = getPaddingLeft() + mMaxOffset*scale;
      break;
     case TEXT_ALIGN_RIGHT:
      baseLineX = getPaddingLeft() + mBarWidth + mMaxOffset*scale;
      break;
    }
   } else {
    switch (mTextAlignment) {
     case TEXT_ALIGN_CENTER:
      baseLineX = getWidth() - getPaddingRight() - mBarWidth/2 - mMaxOffset*scale;
      break;
     case TEXT_ALIGN_RIGHT:
      baseLineX = getWidth() - getPaddingRight() - mMaxOffset*scale;
      break;
     case TEXT_ALIGN_LEFT:
      baseLineX = getWidth() - getPaddingRight() - mBarWidth - mMaxOffset*scale;
      break;
    }
   }

   // draw
   canvas.drawText(
     mIndexItems[i], //item text to draw
     baseLineX, //baseLine X
     baseLineY, // baseLine Y
     mPaint);
  }

  // reset paint
  mPaint.setAlpha(255);
  mPaint.setTextSize(mTextSize);
 }

 /**
  * calculate the scale factor of the item to draw
  *
  * @param index the index of the item in array {@link #mIndexItems}
  * @return the scale factor of the item to draw
  */
 private float getItemScale(int index) {
  float scale = 0;
  if (mCurrentIndex != -1) {
   float distance = Math.abs(mCurrentY - (mIndexItemHeight*index+mIndexItemHeight/2)) / mIndexItemHeight;
   scale = 1 - distance*distance/16;
   scale = Math.max(scale, 0);
  }
  return scale;
 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  if (mIndexItems.length == 0) {
   return super.onTouchEvent(event);
  }

  float eventY = event.getY();
  float eventX = event.getX();
  mCurrentIndex = getSelectedIndex(eventY);

  switch (event.getAction()) {
   case MotionEvent.ACTION_DOWN:
    if (mStartTouchingArea.contains(eventX, eventY)) {
     mStartTouching = true;
     if (!mLazyRespond && onSelectIndexItemListener != null) {
      onSelectIndexItemListener.onSelectIndexItem(mIndexItems[mCurrentIndex]);
     }
    //  invalidate();
     return true;
    } else {
     mCurrentIndex = -1;
     return false;
    }

   case MotionEvent.ACTION_MOVE:
    if (mStartTouching && !mLazyRespond && onSelectIndexItemListener != null) {
     onSelectIndexItemListener.onSelectIndexItem(mIndexItems[mCurrentIndex]);
    }
   //  invalidate();
    return true;

   case MotionEvent.ACTION_UP:
   case MotionEvent.ACTION_CANCEL:
    if (mLazyRespond && onSelectIndexItemListener != null) {
     onSelectIndexItemListener.onSelectIndexItem(mIndexItems[mCurrentIndex]);
    }
    mCurrentIndex = -1;
    mStartTouching = false;
   //  invalidate();
    return true;
  }

  return super.onTouchEvent(event);
 }

 private int getSelectedIndex(float eventY) {
  mCurrentY = eventY - (getHeight()/2 - mBarHeight /2);
  if (mCurrentY <= 0) {
   return 0;
  }

  int index = (int) (mCurrentY / this.mIndexItemHeight);
  if (index >= this.mIndexItems.length) {
   index = this.mIndexItems.length - 1;
  }
  return index;
 }

 private float dp2px(int dp) {
  return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, this.mDisplayMetrics);
 }

 private float sp2px(int sp) {
  return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, this.mDisplayMetrics);
 }

 public void setIndexItems(String... indexItems) {
  mIndexItems = Arrays.copyOf(indexItems, indexItems.length);
  requestLayout();
 }

 public void setTextColor(int color) {
  mTextColor = color;
  mPaint.setColor(color);
  invalidate();
 }

 public void setPosition(int position) {
  if (position != POSITION_RIGHT && position != POSITION_LEFT) {
   throw new IllegalArgumentException("the position must be POSITION_RIGHT or POSITION_LEFT");
  }

  mSideBarPosition = position;
  requestLayout();
 }

 public void setMaxOffset(int offset) {
  mMaxOffset = offset;
  invalidate();
 }

 public void setLazyRespond(boolean lazyRespond) {
  mLazyRespond = lazyRespond;
 }

 public void setTextAlign(int align) {
  if (mTextAlignment == align) {
   return;
  }
  switch (align) {
   case TEXT_ALIGN_CENTER: mPaint.setTextAlign(Paint.Align.CENTER); break;
   case TEXT_ALIGN_LEFT: mPaint.setTextAlign(Paint.Align.LEFT); break;
   case TEXT_ALIGN_RIGHT: mPaint.setTextAlign(Paint.Align.RIGHT); break;
   default:
    throw new IllegalArgumentException(
      "the alignment must be TEXT_ALIGN_CENTER, TEXT_ALIGN_LEFT or TEXT_ALIGN_RIGHT");
  }
  mTextAlignment = align;
  invalidate();
 }

 public void setOnSelectIndexItemListener(WaveSideBarView.OnSelectIndexItemListener onSelectIndexItemListener) {
  this.onSelectIndexItemListener = onSelectIndexItemListener;
 }

 public interface OnSelectIndexItemListener {
  void onSelectIndexItem(String letter);
 }
}

关于“Android怎么实现Recycleview悬浮粘性头部外加右侧字母导航”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。


名称栏目:Android怎么实现Recycleview悬浮粘性头部外加右侧字母导航
网站URL:http://cdxtjz.com/article/phdspc.html

其他资讯