转载请注明原创出处,谢谢!
- 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/