十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
这篇文章主要介绍Android如何实现Recycleview悬浮粘性头部外加右侧字母导航,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
创新互联公司自2013年创立以来,是专业互联网技术服务公司,拥有项目成都网站设计、网站建设网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元香坊做网站,已为上家服务,为香坊各地企业和个人服务,联系电话:18982081108
实现思路:
右侧的联动可以用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 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 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悬浮粘性头部外加右侧字母导航
本文路径:http://shouzuofang.com/article/ggscic.html