欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android仿微信通訊錄列表側(cè)邊欄效果

 更新時(shí)間:2021年09月13日 16:33:35   作者:葉應(yīng)是葉  
這篇文章主要為大家詳細(xì)介紹了Android仿微信通訊錄列表側(cè)邊欄效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

先看Android仿微信通訊錄列表側(cè)邊欄效果圖

這是比較常見的效果了吧

列表根據(jù)首字符的拼音字母來排序,且可以通過側(cè)邊欄的字母索引來進(jìn)行定位。

實(shí)現(xiàn)這樣一個(gè)效果并不難,只要自定義一個(gè)索引View,然后引入一個(gè)可以對(duì)漢字進(jìn)行拼音解析的jar包——pinyin4j-2.5.0即可

首先,先來定義側(cè)邊欄控件View,只要直接畫出來即可。

字母選中項(xiàng)會(huì)變?yōu)榧t色,且滑動(dòng)時(shí)背景會(huì)變色,此時(shí)SideBar并不包含居中的提示文本

public class SideBar extends View {

  private Paint paint = new Paint();

  private int choose = -1;

  private boolean showBackground;

  public static String[] letters = {"#", "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"};

  private OnChooseLetterChangedListener onChooseLetterChangedListener;

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

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

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

  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (showBackground) {
      canvas.drawColor(Color.parseColor("#D9D9D9"));
    }
    int height = getHeight();
    int width = getWidth();
    //平均每個(gè)字母占的高度
    int singleHeight = height / letters.length;
    for (int i = 0; i < letters.length; i++) {
      paint.setColor(Color.BLACK);
      paint.setAntiAlias(true);
      paint.setTextSize(25);
      if (i == choose) {
        paint.setColor(Color.parseColor("#FF2828"));
        paint.setFakeBoldText(true);
      }
      float x = width / 2 - paint.measureText(letters[i]) / 2;
      float y = singleHeight * i + singleHeight;
      canvas.drawText(letters[i], x, y, paint);
      paint.reset();
    }
  }

  @Override
  public boolean dispatchTouchEvent(MotionEvent event) {
    int action = event.getAction();
    float y = event.getY();
    int oldChoose = choose;
    int c = (int) (y / getHeight() * letters.length);
    switch (action) {
      case MotionEvent.ACTION_DOWN:
        showBackground = true;
        if (oldChoose != c && onChooseLetterChangedListener != null) {
          if (c > -1 && c < letters.length) {
            onChooseLetterChangedListener.onChooseLetter(letters[c]);
            choose = c;
            invalidate();
          }
        }
        break;
      case MotionEvent.ACTION_MOVE:
        if (oldChoose != c && onChooseLetterChangedListener != null) {
          if (c > -1 && c < letters.length) {
            onChooseLetterChangedListener.onChooseLetter(letters[c]);
            choose = c;
            invalidate();
          }
        }
        break;
      case MotionEvent.ACTION_UP:
        showBackground = false;
        choose = -1;
        if (onChooseLetterChangedListener != null) {
          onChooseLetterChangedListener.onNoChooseLetter();
        }
        invalidate();
        break;
    }
    return true;
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    return super.onTouchEvent(event);
  }

  public void setOnTouchingLetterChangedListener(OnChooseLetterChangedListener onChooseLetterChangedListener) {
    this.onChooseLetterChangedListener = onChooseLetterChangedListener;
  }

  public interface OnChooseLetterChangedListener {

    void onChooseLetter(String s);

    void onNoChooseLetter();

  }

}

SideBar只是畫出了側(cè)邊欄索引條而已,不包含居中的提示文本,這個(gè)在另一個(gè)布局添加即可

public class HintSideBar extends RelativeLayout implements SideBar.OnChooseLetterChangedListener {

  private TextView tv_hint;

  private SideBar.OnChooseLetterChangedListener onChooseLetterChangedListener;

  public HintSideBar(Context context, AttributeSet attrs) {
    super(context, attrs);
    LayoutInflater.from(context).inflate(R.layout.view_hint_side_bar, this);
    initView();
  }

  private void initView() {
    SideBar sideBar = (SideBar) findViewById(R.id.sideBar);
    tv_hint = (TextView) findViewById(R.id.tv_hint);
    sideBar.setOnTouchingLetterChangedListener(this);
  }

  @Override
  public void onChooseLetter(String s) {
    tv_hint.setText(s);
    tv_hint.setVisibility(VISIBLE);
    if (onChooseLetterChangedListener != null) {
      onChooseLetterChangedListener.onChooseLetter(s);
    }
  }

  @Override
  public void onNoChooseLetter() {
    tv_hint.setVisibility(INVISIBLE);
    if (onChooseLetterChangedListener != null) {
      onChooseLetterChangedListener.onNoChooseLetter();
    }
  }

  public void setOnChooseLetterChangedListener(SideBar.OnChooseLetterChangedListener onChooseLetterChangedListener) {
    this.onChooseLetterChangedListener = onChooseLetterChangedListener;
  }
}

HintSideBar通過回調(diào)接口來更新居中TextView的文本內(nèi)容和可見性

使用到的布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <com.czy.demo.SideBar
    android:id="@+id/sideBar"
    android:layout_width="30dp"
    android:layout_height="match_parent"
    android:layout_alignParentRight="true" />

  <TextView
    android:id="@+id/tv_hint"
    android:layout_width="70dp"
    android:layout_height="70dp"
    android:layout_centerInParent="true"
    android:background="#4b0e0e0e"
    android:gravity="center"
    android:textColor="#ffffff"
    android:textSize="30sp"
    android:visibility="invisible" />

</RelativeLayout>

此時(shí)就完成了索引View的繪制,不過定位功能還需要再通過回調(diào)接口來完成。

引入jar包后,先來設(shè)定一個(gè)工具類,包含一個(gè)可以解析字符串的方法,返回值為首字符對(duì)應(yīng)的拼音首字母或者為包含一個(gè)空格的char類型數(shù)據(jù)。

public class Utils {

  /**
   * 如果字符串的首字符為漢字,則返回該漢字的拼音大寫首字母
   * 如果字符串的首字符為字母,也轉(zhuǎn)化為大寫字母返回
   * 其他情況均返回' '
   *
   * @param str 字符串
   * @return 首字母
   */
  public static char getHeadChar(String str) {
    if (str != null && str.trim().length() != 0) {
      char[] strChar = str.toCharArray();
      char headChar = strChar[0];
      //如果是大寫字母則直接返回
      if (Character.isUpperCase(headChar)) {
        return headChar;
      } else if (Character.isLowerCase(headChar)) {
        return Character.toUpperCase(headChar);
      }
      // 漢語拼音格式輸出類
      HanyuPinyinOutputFormat hanYuPinOutputFormat = new HanyuPinyinOutputFormat();
      hanYuPinOutputFormat.setCaseType(UPPERCASE);
      hanYuPinOutputFormat.setToneType(WITHOUT_TONE);
      if (String.valueOf(headChar).matches("[\\u4E00-\\u9FA5]+")) {
        try {
          String[] stringArray = PinyinHelper.toHanyuPinyinStringArray(headChar, hanYuPinOutputFormat);
          if (stringArray != null && stringArray[0] != null) {
            return stringArray[0].charAt(0);
          }
        } catch (BadHanyuPinyinOutputFormatCombination e) {
          return ' ';
        }
      }
    }
    return ' ';
  }

}

然后再定義一個(gè)實(shí)體類,包含用戶名,電話,用戶名首字符的拼音首字母等三個(gè)屬性
需要實(shí)現(xiàn)Comparable 接口,用于排序

public class User implements Comparable {

  private String userName;

  private String phone;

  private char headLetter;

  public User(String userName, String phone) {
    this.userName = userName;
    this.phone = phone;
    headLetter = Utils.getHeadChar(userName);
  }

  public String getUserName() {
    return userName;
  }

  public String getPhone() {
    return phone;
  }

  public char getHeadLetter() {
    return headLetter;
  }

  @Override
  public boolean equals(Object object) {
    if (this == object) {
      return true;
    }
    if (object == null || getClass() != object.getClass()) {
      return false;
    }
    User that = (User) object;
    return getUserName().equals(that.getUserName()) && getPhone().equals(that.getPhone());
  }

  @Override
  public int compareTo(Object object) {
    if (object instanceof User) {
      User that = (User) object;
      if (getHeadLetter() == ' ') {
        if (that.getHeadLetter() == ' ') {
          return 0;
        }
        return -1;
      }
      if (that.getHeadLetter() == ' ') {
        return 1;
      } else if (that.getHeadLetter() > getHeadLetter()) {
        return -1;
      } else if (that.getHeadLetter() == getHeadLetter()) {
        return 0;
      }
      return 1;
    } else {
      throw new ClassCastException();
    }
  }

}

主布局文件如下

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <android.support.v7.widget.RecyclerView
    android:id="@+id/rv_userList"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

  <com.czy.demo.HintSideBar
    android:id="@+id/hintSideBar"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="right" />

</FrameLayout>

聯(lián)系人列表使用的是RecyclerView,還需要定義一個(gè)Adapter

public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserHolder> {

  private List<User> userList;

  private LayoutInflater inflater;

  public UserAdapter(Context context) {
    inflater = LayoutInflater.from(context);
    userList = new ArrayList<>();
  }

  @Override
  public UserHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = inflater.inflate(R.layout.item_user, parent, false);
    return new UserHolder(view);
  }

  @Override
  public void onBindViewHolder(UserHolder holder, int position) {
    holder.tv_userName.setText(userList.get(position).getUserName());
    holder.tv_phone.setText(userList.get(position).getPhone());
  }

  public void setData(List<User> userList) {
    this.userList.clear();
    this.userList = userList;
  }

  public int getFirstPositionByChar(char sign) {
    if (sign == '#') {
      return 0;
    }
    for (int i = 0; i < userList.size(); i++) {
      if (userList.get(i).getHeadLetter() == sign) {
        return i;
      }
    }
    return -1;
  }

  @Override
  public int getItemCount() {
    return userList.size();
  }

  class UserHolder extends RecyclerView.ViewHolder {

    public TextView tv_userName;

    public TextView tv_phone;

    public UserHolder(View itemView) {
      super(itemView);
      tv_userName = (TextView) itemView.findViewById(R.id.tv_userName);
      tv_phone = (TextView) itemView.findViewById(R.id.tv_phone);
    }
  }

}

以下方法用于獲取聯(lián)系人列表中第一個(gè)首字符為sign的item的位置

public int getFirstPositionByChar(char sign)

主Activity代碼如下

public class MainActivity extends AppCompatActivity implements SideBar.OnChooseLetterChangedListener {

  private List<User> userList;

  private UserAdapter adapter;

  private RecyclerView rv_userList;

  private LinearLayoutManager manager;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_main);
    HintSideBar hintSideBar = (HintSideBar) findViewById(R.id.hintSideBar);
    rv_userList = (RecyclerView) findViewById(R.id.rv_userList);
    hintSideBar.setOnChooseLetterChangedListener(this);
    manager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
    rv_userList.setLayoutManager(manager);
    userList = new ArrayList<>();
    adapter = new UserAdapter(this);
    initData();
    adapter.setData(userList);
    rv_userList.setAdapter(adapter);
  }

  @Override
  public void onChooseLetter(String s) {
    int i = adapter.getFirstPositionByChar(s.charAt(0));
    if (i == -1) {
      return;
    }
    manager.scrollToPositionWithOffset(i, 0);
  }

  @Override
  public void onNoChooseLetter() {

  }
}

initData()用于向Adapter填充數(shù)據(jù)

public void initData() {
    User user1 = new User("陳", "12345678");
    User user2 = new User("趙", "12345678");
    ...
    userList.add(user1);
    userList.add(user2);
    ...
    Collections.sort(userList);
    adapter.notifyDataSetChanged();
  }

這樣,整個(gè)效果就都完成了。

這里提供代碼下載:Android 仿微信通訊錄列表側(cè)邊欄

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 基于Android studio3.6的JNI教程之ncnn人臉檢測mtcnn功能

    基于Android studio3.6的JNI教程之ncnn人臉檢測mtcnn功能

    這篇文章主要介紹了基于Android studio3.6的JNI教程之ncnn之人臉檢測mtcnn功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • Android繪制雙折線圖的方法

    Android繪制雙折線圖的方法

    這篇文章主要為大家詳細(xì)介紹了Android繪制雙折線圖的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Android實(shí)現(xiàn)QQ登錄功能

    Android實(shí)現(xiàn)QQ登錄功能

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)QQ登錄功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • Android中使用protobuf的具體示例

    Android中使用protobuf的具體示例

    本篇文章主要介紹了Android中使用protobuf的具體示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-03-03
  • Android開發(fā)人臉識(shí)別統(tǒng)計(jì)人臉數(shù)

    Android開發(fā)人臉識(shí)別統(tǒng)計(jì)人臉數(shù)

    這篇文章主要介紹了Android開發(fā)人臉識(shí)別統(tǒng)計(jì)人臉數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-10-10
  • Android實(shí)現(xiàn)生成二維碼并保存到相冊(cè)

    Android實(shí)現(xiàn)生成二維碼并保存到相冊(cè)

    這篇文章主要介紹了如何利用Android實(shí)現(xiàn)二維碼的生成,并且保存到本地相冊(cè)。文中的示例代碼講解詳細(xì),感興趣的小伙伴快跟隨小編學(xué)習(xí)一下
    2022-04-04
  • Android如何實(shí)現(xiàn)設(shè)備的異顯功能詳解

    Android如何實(shí)現(xiàn)設(shè)備的異顯功能詳解

    這篇文章主要給大家介紹了關(guān)于Android如何實(shí)現(xiàn)設(shè)備的異顯功能的相關(guān)資料,這篇文章通過示例代碼介紹的非常詳細(xì),對(duì)各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-02-02
  • android內(nèi)存優(yōu)化之圖片優(yōu)化

    android內(nèi)存優(yōu)化之圖片優(yōu)化

    對(duì)圖片本身進(jìn)行操作。盡量不要使用setImageBitmap、setImageResource、BitmapFactory.decodeResource來設(shè)置一張大圖,因?yàn)檫@些方法在完成decode后,最終都是通過java層的createBitmap來完成的,需要消耗更多內(nèi)存
    2012-12-12
  • Rxjava2_Flowable_Sqlite_Android數(shù)據(jù)庫訪問實(shí)例

    Rxjava2_Flowable_Sqlite_Android數(shù)據(jù)庫訪問實(shí)例

    下面小編就為大家分享一篇Rxjava2_Flowable_Sqlite_Android數(shù)據(jù)庫訪問實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-02-02
  • android截屏功能實(shí)現(xiàn)代碼

    android截屏功能實(shí)現(xiàn)代碼

    這篇文章主要為大家詳細(xì)介紹了android截屏功能的實(shí)現(xiàn)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-11-11

最新評(píng)論