安卓當(dāng)下最流行的吸頂效果的實(shí)現(xiàn)(下)
作者:佚名
今天接著上次讓我使用ItemDecoration來完成可推動的懸浮導(dǎo)航欄的效果。
接上文
***步:首先我們來寫一個(gè)類,它起標(biāo)記的作用,來放每一個(gè)item的對應(yīng)的懸浮欄的字符串
- public class NameBean {
- String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
第二步:自定義一個(gè)SectionDecoration 類 繼承 RecyclerView的ItemDecoration
- public class SectionDecoration extends RecyclerView.ItemDecoration {
- private static final String TAG = "SectionDecoration";
- private List<NameBean> dataList;
- private DecorationCallback callback;
- private TextPaint textPaint;
- private Paint paint;
- private int topGap;
- private int alignBottom;
- private Paint.FontMetrics fontMetrics;
- public SectionDecoration(List<NameBean> dataList, Context context, DecorationCallback decorationCallback) {
- Resources res = context.getResources();
- this.dataList = dataList;
- this.callback = decorationCallback;
- //設(shè)置懸浮欄的畫筆---paint
- paint = new Paint();
- paint.setColor(res.getColor(R.color.colorGray));
- //設(shè)置懸浮欄中文本的畫筆
- textPaint = new TextPaint();
- textPaint.setAntiAlias(true);
- textPaint.setTextSize(DensityUtil.dip2px(context, 14));
- textPaint.setColor(Color.DKGRAY);
- textPaint.setTextAlign(Paint.Align.LEFT);
- fontMetrics = new Paint.FontMetrics();
- //決定懸浮欄的高度等
- topGap = res.getDimensionPixelSize(R.dimen.sectioned_top);
- //決定文本的顯示位置等
- alignBottom = res.getDimensionPixelSize(R.dimen.sectioned_alignBottom);
- }
- @Override
- public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
- super.getItemOffsets(outRect, view, parent, state);
- int pos = parent.getChildAdapterPosition(view);
- Log.i(TAG, "getItemOffsets:" + pos);
- String groupId = callback.getGroupId(pos);
- if (groupId.equals("-1")) return;
- //只有是同一組的***個(gè)才顯示懸浮欄
- if (pos == 0 || isFirstInGroup(pos)) {
- outRect.top = topGap;
- if (dataList.get(pos).getName() == "") {
- outRect.top = 0;
- }
- } else {
- outRect.top = 0;
- }
- }
- @Override
- public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
- super.onDraw(c, parent, state);
- int left = parent.getPaddingLeft();
- int right = parent.getWidth() - parent.getPaddingRight();
- int childCount = parent.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View view = parent.getChildAt(i);
- int position = parent.getChildAdapterPosition(view);
- String groupId = callback.getGroupId(position);
- if (groupId.equals("-1")) return;
- String textLine = callback.getGroupFirstLine(position).toUpperCase();
- if (textLine == "") {
- float top = view.getTop();
- float bottom = view.getTop();
- c.drawRect(left, top, right, bottom, paint);
- return;
- } else {
- if (position == 0 || isFirstInGroup(position)) {
- float top = view.getTop() - topGap;
- float bottom = view.getTop();
- //繪制懸浮欄
- c.drawRect(left, top - topGap, right, bottom, paint);
- //繪制文本
- c.drawText(textLine, left, bottom, textPaint);
- }
- }
- }
- }
- @Override
- public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
- super.onDrawOver(c, parent, state);
- int itemCount = state.getItemCount();
- int childCount = parent.getChildCount();
- int left = parent.getPaddingLeft();
- int right = parent.getWidth() - parent.getPaddingRight();
- float lineHeight = textPaint.getTextSize() + fontMetrics.descent;
- String preGroupId = "";
- String groupId = "-1";
- for (int i = 0; i < childCount; i++) {
- View view = parent.getChildAt(i);
- int position = parent.getChildAdapterPosition(view);
- preGroupId = groupId;
- groupId = callback.getGroupId(position);
- if (groupId.equals("-1") || groupId.equals(preGroupId)) continue;
- String textLine = callback.getGroupFirstLine(position).toUpperCase();
- if (TextUtils.isEmpty(textLine)) continue;
- int viewBottom = view.getBottom();
- float textY = Math.max(topGap, view.getTop());
- //下一個(gè)和當(dāng)前不一樣移動當(dāng)前
- if (position + 1 < itemCount) {
- String nextGroupId = callback.getGroupId(position + 1);
- //組內(nèi)***一個(gè)view進(jìn)入了header
- if (nextGroupId != groupId && viewBottom < textY) {
- textY = viewBottom;
- }
- }
- //textY - topGap決定了懸浮欄繪制的高度和位置
- c.drawRect(left, textY - topGap, right, textY, paint);
- //left+2*alignBottom 決定了文本往左偏移的多少(加-->向左移)
- //textY-alignBottom 決定了文本往右偏移的多少 (減-->向上移)
- c.drawText(textLine, left + 2 * alignBottom, textY - alignBottom, textPaint);
- }
- }
- /**
- * 判斷是不是組中的***個(gè)位置
- *
- * @param pos
- * @return
- */
- private boolean isFirstInGroup(int pos) {
- if (pos == 0) {
- return true;
- } else {
- // 因?yàn)槭歉鶕?jù) 字符串內(nèi)容的相同與否 來判斷是不是同意組的,所以此處的標(biāo)記id 要是String類型
- // 如果你只是做聯(lián)系人列表,懸浮框里顯示的只是一個(gè)字母,則標(biāo)記id直接用 int 類型就行了
- String prevGroupId = callback.getGroupId(pos - 1);
- String groupId = callback.getGroupId(pos);
- //判斷前一個(gè)字符串 與 當(dāng)前字符串 是否相同
- if (prevGroupId.equals(groupId)) {
- return false;
- } else {
- return true;
- }
- }
- }
- //定義一個(gè)借口方便外界的調(diào)用
- interface DecorationCallback {
- String getGroupId(int position);
- String getGroupFirstLine(int position);
- }
- }
第三步:在向list集合中先把每一個(gè)item的 起“標(biāo)記”作用的字符串都加進(jìn)去
- setPullAction(comingslist);
- private void setPullAction(List<WaitMVBean.DataBean.ComingBean> comingslist) {
- dataList = new ArrayList<>();
- for (int i = 0; i < comingslist.size(); i++) {
- NameBean nameBean = new NameBean();
- String name0 = comingslist.get(i).getComingTitle();
- nameBean.setName(name0);
- dataList.add(nameBean);
- }
- }
第四步:在setAdapter() 前,為RecyclerView添加ItemDecoration:
- recyclerView.addItemDecoration(new SectionDecoration(dataList,mContext, new SectionDecoration.DecorationCallback() {
- //返回標(biāo)記id (即每一項(xiàng)對應(yīng)的標(biāo)志性的字符串)
- @Override
- public String getGroupId(int position) {
- if(dataList.get(position).getName()!=null) {
- return dataList.get(position).getName();
- }
- return "-1";
- }
- //獲取同組中的***個(gè)內(nèi)容
- @Override
- public String getGroupFirstLine(int position) {
- if(dataList.get(position).getName()!=null) {
- return dataList.get(position).getName();
- }
- return "";
- }
- }));
這樣就完成了~
再看一眼最終效果感受一下:
責(zé)任編輯:龐桂玉
來源:
安卓開發(fā)精選