Android效果,SideBar 和RecyclerView联动的悬浮效果

转载请注明原创出处,谢谢!
  • GitHub: @Ricco
类似效果图
  • 类似效果图 ↑
  • 类似效果图 ↑
  • 类似效果图 ↑
  • 重要的画说三遍
public class MyActivity extends BaseActivity implements SideBar.OnSelectListener {
    @Bind(R.id.tv_suspension_bar)
    TextView tvSuspensionBar; // 悬浮
    @Bind(R.id.recycler)
    RecyclerView recycler;
    @Bind(R.id.side_bar)
    SideBar sideBar;
    private int mSuspensionHeight = 0; // 高度
    private int mCurrentPosition = 0; // 当前悬浮
    private LinearLayoutManager layoutManager;
    private MyAdapter adapter = new MyAdapter();

    @Override
    public int getLayoutRes() {
        return R.layout.activity_my;
    }

    @Override
    public void afterLoadLayout(Bundle savedInstanceState) {
        layoutManager = new LinearLayoutManager(context);
        recycler.setLayoutManager(layoutManager);
        recycler.setAdapter(adapter);
        sideBar.setOnSelectListener(this);
        adapter.setOnItemChildClickListener(this);
        recycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                mSuspensionHeight = tvSuspensionBar.getHeight();
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (mCurrentPosition > 0) {
                    if (adapter.getData().get(mCurrentPosition + 1).isShowFirm()) {
                        View view = layoutManager.findViewByPosition(mCurrentPosition + 1);
                        if (view != null) {
                            if (view.getTop() <= mSuspensionHeight) {
                                tvSuspensionBar.setY(-(mSuspensionHeight - view.getTop()));
                            } else {
                                tvSuspensionBar.setY(0);
                            }
                        }
                    }
                }
                if (mCurrentPosition != layoutManager.findFirstVisibleItemPosition()) {
                    mCurrentPosition = layoutManager.findFirstVisibleItemPosition();
                    tvSuspensionBar.setY(0);
                    tvSuspensionBar.setText(adapter.getData().get(mCurrentPosition).getFirstEng());
                }
            }
        });
        getData();
    }

    @Override
    public void onSelect(String s) {
        sideBar.setOnSelectListener(new SideBar.OnSelectListener() {
            @Override
            public void onSelect(String s) {
                // 根据选中的首字母移动到指定位置
                layoutManager.scrollToPositionWithOffset(adapter.getScrollPosition(s), 0);
            }
        });
    }


    private void getData() {
        ...
        data是网络请求回来的数据
        ...
    
        // 处理数据
        // 根据字母分类
        List characterList = new ArrayList<>(); // 首字母
        Map> map = new LinkedHashMap<>();
        for (Entity bean : data) {
            if (map.containsKey(bean.getFirstEng())) {
                map.get(bean.getFirstEng()).add(bean);
            } else {
                List list = new ArrayList<>();
                list.add(bean);
                map.put(bean.getFirstEng(), list);
                characterList.add(bean.getFirstEng());
            }
        }
        // 合并
        List newList = new ArrayList<>();
        for (List list : map.values()) {
            list.get(0).setShowFirm(true); // 每个分类的第一个显示字母
            list.get(list.size() - 1).setShowLine(true); // 每个分类的最后一个隐藏分割线
            newList.addAll(list);
        }
        // 设置activity的悬浮
        if (newList.size() > 0) {
            tvSuspensionBar.setText(newList.get(0).getFirstEng());
        }
        adapter.setCharacterList(characterList);
        adapter.setNewData(newList);
    }
}
public class MyAdapter extends BaseQuickAdapter {

    public MyAdapter() {
        super(R.layout.adapter_my);
    }

    @Override
    protected void convert(BaseViewHolder helper, Entity item) {
        helper.setText(R.id.tv_character, "" + item.getFirstEng())
                .setText(R.id.tv_name, "" + item.getName())
                .setGone(R.id.tv_character, item.isShowFirm()) // 每个分类的第一个有字母
                .setGone(R.id.line, !item.isShowLine()); // 每个分类的最后一个没有线
    }

    private List mCharacterList;

    public void setCharacterList(List characterList) {
        mCharacterList = characterList;
    }

    public int getScrollPosition(String character) {
        if (mData.size() != 0 && mCharacterList != null && mCharacterList.size() != 0) {
            if (mCharacterList.contains(character)) {
                for (int i = 0; i < mData.size(); i++) {
                    if (mData.get(i).getFirstEng().equals(character)) {
                        return i;
                    }
                }
            }
        }
        return -1; // -1不会滑动
    }
}
public class SideBar extends View {

    //SideBar上显示的字母
    private static final String[] CHARACTERS = {"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"};

    //SideBar的高度
    private int width;
    //SideBar的宽度
    private int height;
    //SideBar中每个字母的显示区域的高度
    private float cellHeight;
    //画字母的画笔
    private Paint characterPaint;
    //SideBar上字母绘制的矩形区域
    private Rect textRect;
    //手指触摸在SideBar上的横纵坐标
    private float touchY;
    private float touchX;

    private OnSelectListener listener;

    public SideBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

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

    public SideBar(Context context) {
        super(context);
        init(context);
    }

    //初始化操作
    private void init(Context context) {
        textRect = new Rect();
        characterPaint = new Paint();
        characterPaint.setColor(0xFF4980F2);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right,
                            int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (changed) { //在这里测量SideBar的高度和宽度
            width = getMeasuredWidth();
            height = getMeasuredHeight();
            //SideBar的高度除以需要显示的字母的个数,就是每个字母显示区域的高度
            cellHeight = height * 1.0f / CHARACTERS.length;
            //根据SideBar的宽度和每个字母显示的高度,确定绘制字母的文字大小,这样处理的好处是,对于不同分辨率的屏幕,文字大小是可变的
            int textSize = (int) ((width > cellHeight ? cellHeight : width) * (3.0f / 4));
            characterPaint.setTextSize(textSize);
        }
    }

    //画出SideBar上的字母
    private void drawCharacters(Canvas canvas) {
        for (int i = 0; i < CHARACTERS.length; i++) {
            String s = CHARACTERS[i];
            //获取画字母的矩形区域
            characterPaint.getTextBounds(s, 0, s.length(), textRect);
            //根据上一步获得的矩形区域,画出字母
            canvas.drawText(s,
                    (width - textRect.width()) / 2f,
                    cellHeight * i + (cellHeight + textRect.height()) / 2f,
                    characterPaint);
        }
    }

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

    //根据手指触摸的坐标,获取当前选择的字母
    private String getHint() {
        int index = (int) (touchY / cellHeight);
        if (index >= 0 && index < CHARACTERS.length) {
            return CHARACTERS[index];
        }
        return null;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //获取手指触摸的坐标
                touchX = event.getX();
                touchY = event.getY();
                if (listener != null && touchX > 0) {
                    listener.onSelect(getHint());
                }
                /*if (listener != null && touchX < 0) {
                    listener.onMoveUp(getHint());
                }*/
                return true;
            case MotionEvent.ACTION_MOVE:
                //获取手指触摸的坐标
                touchX = event.getX();
                touchY = event.getY();
                if (listener != null && touchX > 0) {
                    listener.onSelect(getHint());
                }
                /*if (listener != null && touchX < 0) {
                    listener.onMoveUp(getHint());
                }*/
                return true;
            case MotionEvent.ACTION_UP:
                touchY = event.getY();
                /*if (listener != null) {
                    listener.onMoveUp(getHint());
                }*/
                return true;
        }
        return super.onTouchEvent(event);
    }

    //监听器,监听手指在SideBar上按下和抬起的动作
    public interface OnSelectListener {
        void onSelect(String s);

//        void onMoveUp(String s);
    }

    //设置监听器
    public void setOnSelectListener(OnSelectListener listener) {
        this.listener = listener;
    }
}
public class Entity {
    private String firstEng; // 首字母
    private String name; // 内容
    private boolean showFirm; // 是否显示上面内容
    private boolean showLine; // 是否显示分割线
}

activity_my.xml ↓




    

    

    

adapter_my.xml ↓




    

    

    


MyAdapter 基于BRVAH 编写 BRVAH

BRVAH官方使用指南:https://www.jianshu.com/p/b343fcff51b0/

你可能感兴趣的:(Android效果,SideBar 和RecyclerView联动的悬浮效果)