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'