Android自定义字母索引
2020-03-30 本文已影响0人
落雨敏
Android字母索引这个功能还是很常见的,例如:电话联系人,城市选择等一些功能都会用到。轮子已造好 直接使用,Github地址。
效果图:

自定义分析:
1、自定义View用 Paint 画笔绘制右边的 [ A - Z ]
public class SideBarSortView extends View {
private Canvas mCanvas;
private int mSelectIndex = 0;
private float mTextSize;
private int mTextColor;
private float mTextSizeChoose;
private int mTextColorChoose;
public void setmTextSize(float mTextSize) {
this.mTextSize = mTextSize;
}
public void setmTextColor(int mTextColor) {
this.mTextColor = mTextColor;
}
public void setmTextSizeChoose(float mTextSizeChoose) {
this.mTextSizeChoose = mTextSizeChoose;
}
public void setmTextColorChoose(int mTextColorChoose) {
this.mTextColorChoose = mTextColorChoose;
}
//这里也可以传入数组方式
public static String[] mList = {"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","#"};
public Paint paint = new Paint();
public SideBarSortView(Context context) {
super(context);
}
public SideBarSortView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
this.mCanvas=canvas;
paintText();
}
private void paintText(){
//计算每一个字母的高度,总告诉除以字母集合的高度就可以
int height = (getHeight()) / mList.length;
for (int i = 0; i < mList.length; i++) {
if(i==mSelectIndex){
paint.setColor(mTextColorChoose);
paint.setTextSize( mTextSizeChoose);
}else {
paint.setColor(mTextColor);
paint.setTextSize( mTextSize);
}
paint.setAntiAlias(true);//设置抗锯齿
paint.setTypeface(Typeface.DEFAULT_BOLD);
//计算每一个字母x轴
float paintX = getWidth() / 2F - paint.measureText(mList[i]) / 2;
//计算每一个字母Y轴
int paintY = height * i + height;
//绘画出来这个TextView
mCanvas.drawText(mList[i], paintX, paintY, paint);
//画完一个以后重置画笔
paint.reset();
}
}
}
2、onTouch()事件 实现选中的字母变色、中间高亮字母,并设置回调监听来联动Listview的item位置
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
int index = (int) (event.getY() / getHeight() * mList.length);
if (index >= 0 && index < mList.length) {
if(mClickListener!=null){
//滑动A-Z字母联动外层数据
mClickListener.onSideBarScrollUpdateItem(mList[index]);
}
mSelectIndex=index;
invalidate();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if(mClickListener!=null){
mClickListener.onSideBarScrollEndHideText();
}
break;
}
return true;
}
3、滑动结束设置隐藏中间高亮字母控件
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if(mClickListener!=null){
//隐藏高亮文字
mClickListener.onSideBarScrollEndHideText();
}
break;
4、外层联动滚动控件(eg:Listview)监听滑动事件设置右边字母位置
//自定义字母控件SideBarSortView
public void onitemScrollUpdateText(String word) {
for (int i = 0; i < mList.length; i++) {
if(mList[i].equals(word)&& mSelectIndex != i ){
mSelectIndex = i;
invalidate();
}
}
}
//自定义组合控件SideBarLayout(字母+高亮TextView)
public void OnItemScrollUpdateText(String word) {
if(mListener!=null){
mSortView.onitemScrollUpdateText(word);
}
}
然后在 Activity 实现一下Recyclerview联动使用
(1)xml布局使用控件
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:divider="@null"
android:overScrollMode="never"
android:scrollbars="none" />
//字体颜色、大小为自定义
<com.lzj.sidebar.SideBarLayout
android:id="@+id/sidebar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:sidebarSelectTextColor="@color/hotpink"
app:sidebarUnSelectTextColor="@color/colorPrimary"
app:sidebarSelectTextSize="12sp"
app:sidebarUnSelectTextSize="10sp"
app:sidebarWordBackground="@drawable/sort_text_bg"
app:sidebarWordTextColor="@color/darkred"
app:sidebarWordTextSize="45sp">
</com.lzj.sidebar.SideBarLayout>
</FrameLayout>
(2)MainActivity初始化数据,使用pinyin4j:2.5.1进行汉字转拼音,具体实现根据公司业务来定
(3)RecyclerView实现的联动,参考如下:
//侧边栏滑动 --> item
sidebarView.setSideBarLayout(new SideBarLayout.OnSideBarLayoutListener() {
@Override
public void onSideBarScrollUpdateItem(String word) {
//循环判断点击的拼音导航栏和集合中姓名的首字母,如果相同recyclerView就跳转指定位置
for (int i = 0; i < mList.size(); i++) {
if (mList.get(i).getWord().equals(word)) {
recyclerView.smoothScrollToPosition(i);
break;
}
}
}
});
//item滑动 --> 侧边栏
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int scrollState) {
super.onScrollStateChanged(recyclerView, scrollState);
mScrollState = scrollState;
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (mScrollState != -1) {
//第一个可见的位置
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
//判断是当前layoutManager是否为LinearLayoutManager
// 只有LinearLayoutManager才有查找第一个和最后一个可见view位置的方法
int firstItemPosition=0;
if (layoutManager instanceof LinearLayoutManager) {
LinearLayoutManager linearManager = (LinearLayoutManager) layoutManager;
//获取第一个可见view的位置
firstItemPosition = linearManager.findFirstVisibleItemPosition();
}
sidebarView.OnItemScrollUpdateText(mList.get(firstItemPosition).getWord());
if (mScrollState == RecyclerView.SCROLL_STATE_IDLE) {
mScrollState = -1;
}
}
}
});
(4)在EditText输入框的afterTextChanged()方法实现正则匹配规则,参考如下:
@Override
public void afterTextChanged(Editable s) {
if (mList == null || mList.size() <= 0) {
return;
}
String keyWord = s.toString();
Log.i("test","------------key="+keyWord);
if (!keyWord.equals("")) {
if (matcherSearch(keyWord, mList).size() > 0) {
sidebarView.OnItemScrollUpdateText(matcherSearch(keyWord, mList).get(0).getWord());
}
mSortAdaper.setNewData(matcherSearch(keyWord, mList));
mSortAdaper.notifyDataSetChanged();
} else {
sidebarView.OnItemScrollUpdateText(mList.get(0).getWord());
mSortAdaper.setNewData(mList);
mSortAdaper.notifyDataSetChanged();
}
}
//正则匹配参考 先首字母
public List<SortBean> matcherSearch(String keyword, List<SortBean> list) {
List<SortBean> results = new ArrayList<>();
String patten = Pattern.quote(keyword);
Pattern pattern = Pattern.compile(patten, Pattern.CASE_INSENSITIVE);
for (int i = 0; i < list.size(); i++) {
//根据首字母
Matcher matcherWord = pattern.matcher((list.get(i)).getWord());
//根据拼音
Matcher matcherPin = pattern.matcher((list.get(i)).getPinyin());
//根据简拼
Matcher matcherJianPin = pattern.matcher((list.get(i)).getJianpin());
//根据名字
Matcher matcherName = pattern.matcher((list.get(i)).getName());
if (matcherWord.find() || matcherPin.find() || matcherName.find() || matcherJianPin.find()) {
results.add(list.get(i));
}
}
return results;
}
结尾
各位看官如果本文对你有帮助,请点个赞吧。
Androidx版本,请前往github源码。
implementation 'com.github.lzjin:SideBarView:1.0'