android之省市区三级联动,recyclerview首字母悬浮列表

什么都是假的,先看效果图


三级联动

首先感谢这两个作者

https://github.com/venshine/WheelView

https://github.com/wulianghuan/Cascade_Master

这个效果我只是搬运工,整合了这两个作者的东西,弄出来的,也没啥好说的,就是一个popupwin,后面我会放源码,大家自行下载观看(不要积分,给个start就行)

recyclerview首字母悬浮效果

思路主要分为三点:

1、首先拿到数据的拼音的首字母,排序

2、在adapter里面检查首字母第一次出现的位置,从而控制显示隐藏

3、首字母出现的位置设置tag,跟主页面的字母进行动画替换(重点)

4、点击侧边的字母进行联动

我们先通过 android源码的HanziToPinyin这个类,把我们的数据转成拼音,然后截取首字母

/**
 * 比较器,比较拼音的首字母
 */
public class PinYinComparator implements Comparator<PinYinComparator.CityBean> {
    @Override
    public int compare(CityBean lhs, CityBean rhs) {
        return lhs.getSortLetter().compareTo(rhs.getSortLetter());
    }

    /**
     * 实体类,用来存储,汉字,和对应的首字母的拼音
     */
    public static class CityBean {
        private String name;
        private String sortLetter;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getSortLetter() {
            return sortLetter;
        }

        public void setSortLetter(String sortLetter) {
            this.sortLetter = sortLetter;
        }
    }


    /**
     * 汉字转拼音
     * @param input 传入的汉字
     * @return
     */
    public static String getPinYin(String input) {
        ArrayList tokens = HanziToPinyin.getInstance().get(input);
        StringBuilder sb = new StringBuilder();
        if (tokens != null && tokens.size() > 0) {
            Iterator iterator = tokens.iterator();
            while (iterator.hasNext()) {
                HanziToPinyin.Token token = (HanziToPinyin.Token) iterator.next();
                if (2 == token.type) {
                    sb.append(token.target);
                } else {
                    sb.append(token.source);
                }
            }
        }
        return sb.toString().toUpperCase();
    }

}
 后面拿到数据,循环调用上面的getPinYin就能得到字母,然后截取第一个,在存到上面的实体类里面,然后使用比较器进行排序 Collections. sort ( mCityList , new PinYinComparator());

到这里我们的第一步就搞定了。

 下面我们来看,控制首字母的显示和隐藏,我们来看adapter的onBindViewHolder
方法,我们先拿到实体类,然后拿首字母,通过getPositionForSelect得到这个字母在排序中的位置,而我们的recyclerview的position到达这个位置时就显示首字母和设置tag,否则的话就隐藏,这里设置tag是为了下一步的进行。

    PinYinComparator.CityBean info = mData.get(position);

        holder.name.setText(info.getName());
        char selection = info.getSortLetter().charAt(0);
        int letterPosition = getPositionForSelection(selection);
        if (letterPosition == position) {
            holder.letter_tv.setText(info.getSortLetter());
            holder.letter_tv.setVisibility(View.VISIBLE);
            holder.itemView.setTag(HAS_STICKY_VIEW);
        } else {
            holder.letter_tv.setVisibility(View.GONE);
            holder.itemView.setTag(NONE_STICKY_VIEW);
        }
 动画替换

在主页面,我们用一个和字母一样的布局跟recyclerview嵌套在一起,其实那个悬浮头就是在主页面里的布局,

而不是item的那个字母头,我们只是监听滑动,到了我们上面设置tag的地方,就让他滑动他自身的高度,就是下面的

mLetterText

{
        View letterView = mRecyclerView.findChildViewUnder(mLetterText.getMeasuredWidth() / 2, 3);
        if (letterView != null && letterView.getContentDescription() != null) {
            mLetterText.setText(String.valueOf(letterView.getContentDescription()));
        }

        View recyclerItem = mRecyclerView.findChildViewUnder(mLetterText.getMeasuredWidth() / 2,
                mLetterText.getMeasuredHeight() + 1);

        if (recyclerItem != null && recyclerItem.getTag() != null) {
            //这个recycleritem其实是和mLetterText一样的
            //但是滑动recyclerview他的top会改变,此时,我们就让mLetterText跟着改变
            int deltaY = recyclerItem.getTop() - mLetterText.getMeasuredHeight();

            if ((int) recyclerItem.getTag() == mCityAdapter.HAS_STICKY_VIEW) {
                if (recyclerItem.getTop() > 0) {
                    mLetterText.setTranslationY(deltaY);
                } else {
                    mLetterText.setTranslationY(0);
                }
            } else if ((int) recyclerItem.getTag() == mCityAdapter.NONE_STICKY_VIEW) {
                mLetterText.setTranslationY(0);
            }
        }
    }

 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                letterScroll();
            }
        });

绘制导航字母条

这里难度不大,只是我们绘制的时候要知道,每个字母的x和y坐标应该怎么定,y坐标是计算空件自身的高度,然后除于27(还有一个#)

这样就得到每个字母的y坐标了,x就是控件自身的宽度的一般减去字母的宽度的一半。如何知道我们点击了哪个字母呢

看下我们的公式就明白了:点击的字母/27=点击的y坐标/总高度

而我们求:点击的字母=(27*点击的y坐标)/总高度

/**
 * 字母导航控件
 */
public class NavigationView extends View {
    private Paint mPaint;
    private String[] mDate = new String[]{"A", "B", "C", "D", "E", "F",
            "G", "H", "I", "J", "K", "L", "N", "M", "O", "P", "Q", "R",
            "S", "T", "U", "V", "W", "X", "Y", "Z", "#"};
    private int position = -1;
    private int mHeight;

    public NavigationView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setTextSize(23);
        mPaint.setTypeface(Typeface.DEFAULT_BOLD);
    }

    public NavigationView(Context context) {
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mHeight = getHeight();
        int width = getWidth();
        int simpleHeight = mHeight / mDate.length;
        for (int i = 0; i < mDate.length; i++) {
            mPaint.setColor(Color.BLUE);
            if (i == position) {
                mPaint.setColor(Color.RED);
            }
            float x = (width - mPaint.measureText(mDate[i])) / 2.0f;
            float y = simpleHeight * (i + 1);
            canvas.drawText(mDate[i], x, y, mPaint);
        }
    }

    @SuppressLint("NewApi")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int y = (int) event.getY();
        int oldPosition = position;
        int c = (y * mDate.length) / mHeight;
        switch (event.getAction()) {

            case MotionEvent.ACTION_UP:
                setBackground(new ColorDrawable(0));
                if (mDialog != null) {
                    mDialog.setVisibility(View.GONE);
                }
                position = -1;
                break;

            default:
                setBackgroundColor(Color.parseColor("#EEE5DE"));
                if (c >= 0 && c < mDate.length && c != oldPosition) {
                    if (mOnTouchItemListener != null) {
                        mOnTouchItemListener.onTouch(mDate[c]);
                        Log.e("------", "onTouchEvent: "+mDate[c] );
                    }
                    if (mDialog != null) {
                        mDialog.setText(mDate[c]);
                        mDialog.setVisibility(View.VISIBLE);
                    }
                }
                position = c;
                invalidate();
                break;
        }

        return true;
    }

    private TextView mDialog;

    public void setDialog(TextView dialog) {
        mDialog = dialog;
    }

    private OnTouchItemListener mOnTouchItemListener;

    public void setOnTouchItemListener(OnTouchItemListener onTouchItemListener) {
        mOnTouchItemListener = onTouchItemListener;
    }

    public interface OnTouchItemListener {
        void onTouch(String var1);
    }

}
大功告成,github地址:https://github.com/WoBuShuo/SelectUtil














  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值