先看Android仿微信通讯录列表侧边栏效果图

这是比较常见的效果了吧

列表根据首字符的拼音字母来排序,且可以通过侧边栏的字母索引来进行定位。

实现这样一个效果并不难,只要自定义一个索引View,然后引入一个可以对汉字进行拼音解析的jar包——pinyin4j-2.5.0即可

首先,先来定义侧边栏控件View,只要直接画出来即可。

字母选中项会变为红色,且滑动时背景会变色,此时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();

//平均每个字母占的高度

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只是画出了侧边栏索引条而已,不包含居中的提示文本,这个在另一个布局添加即可

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通过回调接口来更新居中TextView的文本内容和可见性

使用到的布局

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/sideBar"

android:layout_width="30dp"

android:layout_height="match_parent"

android:layout_alignParentRight="true" />

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" />

此时就完成了索引View的绘制,不过定位功能还需要再通过回调接口来完成。

引入jar包后,先来设定一个工具类,包含一个可以解析字符串的方法,返回值为首字符对应的拼音首字母或者为包含一个空格的char类型数据。

public class Utils {

/**

* 如果字符串的首字符为汉字,则返回该汉字的拼音大写首字母

* 如果字符串的首字符为字母,也转化为大写字母返回

* 其他情况均返回' '

*

* @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 ' ';

}

}

然后再定义一个实体类,包含用户名,电话,用户名首字符的拼音首字母等三个属性

需要实现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();

}

}

}

主布局文件如下

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/rv_userList"

android:layout_width="match_parent"

android:layout_height="match_parent" />

android:id="@+id/hintSideBar"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_gravity="right" />

联系人列表使用的是RecyclerView,还需要定义一个Adapter

public class UserAdapter extends RecyclerView.Adapter {

private List 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 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);

}

}

}

以下方法用于获取联系人列表中第一个首字符为sign的item的位置

public int getFirstPositionByChar(char sign)

主Activity代码如下

public class MainActivity extends AppCompatActivity implements SideBar.OnChooseLetterChangedListener {

private List 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填充数据

public void initData() {

User user1 = new User("陈", "12345678");

User user2 = new User("赵", "12345678");

...

userList.add(user1);

userList.add(user2);

...

Collections.sort(userList);

adapter.notifyDataSetChanged();

}

这样,整个效果就都完成了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

android自定义sidebar,Android仿微信通讯录列表侧边栏效果相关推荐

  1. android 字母索引三方,Android ListView字母索引(仿微信通讯录列表)

    布局代码 xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_paren ...

  2. 【uniapp前端组件】仿微信通讯录列表组件

    仿微信通讯录列表组件 示例图 前言 仿微信通讯录列表组件,可实现通讯列表以及选择多个联系人功能. 组件介绍 本组件有三个自定义组件构成,都已经集成在bugking7-contact-list中,该组件 ...

  3. android bmob 朋友圈,仿微信朋友圈视频效果 – MVideo

    MVideo 仿微信朋友圈视频效果,可以拖拽及缩放,视频查看,基于ijkplayer. Demo 入门 Step 1:在buil文件中添加JitPack仓库: allprojects { reposi ...

  4. Android自定义ListView实现仿微信侧滑删除

    经常在遇到问题第一时间都会在网上搜索解决的方法,因此看到很多前辈们的比较精辟的技术文章,学习了很多东西,现在将自己平时工作中开发的一些小功能坐下总结,也写出来,既方便自己理清思路记忆功能块实现思路,又 ...

  5. Android自定义View分享——仿微信朋友圈图片合并效果

    写在前面 笔者近来在学习Android自定义View,收集了一些不算复杂但又"长得"还可以的自定义View效果实现,之前分享过两个效果:一个水平的进度条,一个圆形温度显示器,如果你 ...

  6. Android使用RecyclerView实现仿微信联系人列表

    现在联系人列表基本都是按照字母或者拼音来进行分类,右边有一排字母供用户快速定位到指定的字母位置,效果图如下: OK,输入的联系人类型可能有很多种,比如汉字.英文.数字.特殊符号等等,其中汉字会转化成拼 ...

  7. Android 自定义Switch,仿微信开关键Switch

    switch (changeFragmentEvent.getViewId()) {//启动设备(安卓接收)case 1:textView.setText("vvvvv555"+c ...

  8. Android 自定义seekbar【仿微信联系人】

    /** *  * 转载请标明出处:http://blog.csdn.net/u013598111/article/details/50452578 *   @author:[JunTao_sun]   ...

  9. RN仿微信通讯录列表

    源码在此 先看一下预览图效果: pic1.jpg 首先通过构造器初始化state constructor(props) {super(props);this.state = {//Global这里是全 ...

  10. Android自定义View实现仿QQ实现运动步数效果

    效果图: 1.attrs.xml中 <declare-styleable name="QQStepView"><attr name="outerColo ...

最新文章

  1. 导入语句 python_Python导入语句说明
  2. 不装客户端连接mysql_C#不安装oracle客户端,如何连接到oracle数据库
  3. 重磅!阿里开源自研语音识别模型DFSMN,准确率高达96.04%
  4. Django购物网站使用说明
  5. kafka生产者开发方式
  6. Mask Network与Conflux发起联合Bounty
  7. java 整数加减乘除_java实现超大整数加减乘除四则运算
  8. 分析一个在高并发下的财务支付锁的问题
  9. tomcat配置gc日志输出
  10. 一键进入高通9008模式_想闯中国智能汽车的高通和想花200亿的威马
  11. 使用APICloud AVM多端框架开发app通讯录功能
  12. unity 视频录制总结
  13. 课后实践9:以拼多多为例,原型设计
  14. 国产软件不背黑锅,4款强大又实用的电脑软件,用了舍不得卸载
  15. 汽车轮毂识别项目介绍
  16. 网络设备和常见网络拓扑
  17. VBA使用FileSystemObject将读取或写入文本文件
  18. 排序算法-冒泡排序的时间复杂度分析
  19. 10 款趋势策略的比较分析
  20. Linux设备驱动开发(5.4.58)-3-NEWCHR

热门文章

  1. 低通滤波与RC振荡产生正弦波
  2. springboot集成webservice接口
  3. PCB Layout的10个细节
  4. 有多少个斐波那契子数列(微软笔试题)
  5. comsol 学习笔记【基础知识,磁场与结构场耦合为主】
  6. 计算机的生产过程,笔记本电脑生产流程介绍 .pptx
  7. MFC 通用对话框之“查找替换“对话框
  8. [转]WebQQ登录过程分析
  9. python文件粉碎传输_如何自己实现文件粉碎机?
  10. MindMeld中文文档--2.构建会话应用程序的不同方法[Different Approaches for Building Conversational Applications]