类似于微信通讯录的界面Demo

这几天遇到一个项目需要向微信通讯录那样展示联系人,这里我做了一个简单的例子,希望可以帮助大家

先来看下界面的实现效果

        

上面的是在搜索框搜索时的结果,和点击后边的字母跳转到相应 的字母对应名字地方,并且显示你选择的字母

好了,现在我们来整理一下思路,怎么实现这中效果呢。

第一步,我们肯定是要有一个这样的界面

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical" >

<RelativeLayout

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:background="@color/yellow_page_search_bg"

android:paddingBottom="5dp"

android:paddingLeft="10dp"

android:paddingRight="10dp"

android:paddingTop="5dp" >

<com.mulu.widget.CustomEditText

android:id="@+id/school_friend_member_search_input"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_gravity="center_vertical"

android:background="@drawable/bg_search_input"

android:drawableLeft="@drawable/ic_search"

android:drawablePadding="5dp"

android:drawableRight="@drawable/ic_edit_text_delbtn"

android:freezesText="true"

android:gravity="center_vertical"

android:hint="@string/school_friend_search_hint"

android:imeOptions="actionSearch"

android:singleLine="true"

android:textColor="@color/black"

android:textColorHint="@color/login_form_hint"

android:textSize="14sp" />

</RelativeLayout>

<TextView

android:layout_width="fill_parent"

android:layout_height="1px"

android:background="@drawable/bg_cut_line" />

<FrameLayout

android:layout_width="fill_parent"

android:layout_height="wrap_content" >

<ListView

android:id="@+id/school_friend_member"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:cacheColorHint="@color/transparent"

android:divider="@drawable/bg_cut_line"

android:dividerHeight="1px"

android:fadingEdge="none"

android:listSelector="@color/transparent"

android:scrollbars="none" >

</ListView>

<TextView

android:id="@+id/school_friend_dialog"

android:layout_width="80.0dip"

android:layout_height="80.0dip"

android:layout_gravity="center"

android:background="@drawable/bg_show_head_toast"

android:gravity="center"

android:textColor="#ffffffff"

android:textSize="30.0dip"

android:visibility="invisible" />

<com.mulu.widget.SideBar

android:id="@+id/school_friend_sidrbar"

android:layout_width="30dp"

android:layout_height="fill_parent"

android:layout_gravity="right|center" />

</FrameLayout>

</LinearLayout>

这个界面引用了自定义的一些空间CustomEditText,SideBar,一个是最上面的搜索输入框,一个是要显示上图对应绿色的x那个布局,还有一些资源文件,我都放在相应的res下drawable-hdip这个包中,等会我会把相应的全部代码打包上传上来的,有需要的可以下载看看

下面我们来自定义我们需要的控件

package com.mulu.widget;

import android.content.Context;

import android.graphics.Rect;

import android.graphics.drawable.Drawable;

import android.text.Editable;

import android.text.TextWatcher;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.widget.EditText;

/**

* 自定义文本输入框,增加清空按钮

*

* @author  shaozc

*

*/

public class CustomEditText extends EditText {

private Drawable mLeft, mTop, mRight, mBottom;

private Rect mBounds;

public CustomEditText(Context context) {

super(context);

init();

}

public CustomEditText(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

init();

}

public CustomEditText(Context context, AttributeSet attrs) {

super(context, attrs);

init();

}

private void init() {

setDrawable();

// 增加文本监听器.

addTextChangedListener(new TextWatcher() {

@Override

public void onTextChanged(CharSequence s, int start, int before, int count) {

}

@Override

public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

@Override

public void afterTextChanged(Editable s) {

setDrawable();

}

});

}

// 输入框右边的图标显示控制

private void setDrawable() {

if (length() == 0) {

setCompoundDrawables(mLeft, mTop, null, mBottom);

} else {

setCompoundDrawables(mLeft, mTop, mRight, mBottom);

}

}

@Override

public void setCompoundDrawables(Drawable left, Drawable top, Drawable right, Drawable bottom) {

if (mLeft == null) {

this.mLeft = left;

}

if (mTop == null) {

this.mTop = top;

}

if (mRight == null) {

this.mRight = right;

}

if (mBottom == null) {

this.mBottom = bottom;

}

super.setCompoundDrawables(left, top, right, bottom);

}

// 输入事件处理

@Override

public boolean onTouchEvent(MotionEvent event) {

if (mRight != null && event.getAction() == MotionEvent.ACTION_UP) {

this.mBounds = mRight.getBounds();

mRight.getIntrinsicWidth();

int eventX = (int) event.getX();

int width = mBounds.width();

int right = getRight();

int left = getLeft();

if (eventX > (right - width * 2 - left)) {

setText("");

event.setAction(MotionEvent.ACTION_CANCEL);

}

}

return super.onTouchEvent(event);

}

@Override

protected void finalize() throws Throwable {

super.finalize();

this.mLeft = null;

this.mTop = null;

this.mRight = null;

this.mBottom = null;

this.mBounds = null;

}

}

接下来是右边的字母布局控件

package com.mulu.widget;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.drawable.ColorDrawable;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.View;

import android.widget.TextView;

import com.mulu.activity.R;

public class SideBar extends View {

// 触摸事件

private OnTouchingLetterChangedListener onTouchingLetterChangedListener;

// 26个字母

public static String[] b = { "☆", "#", "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 int choose = -1;// 选中

private Paint paint = new Paint();

private TextView mTextDialog;

public void setTextView(TextView mTextDialog) {

this.mTextDialog = mTextDialog;

}

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

// 获取焦点改变背景颜色.

int height = getHeight();// 获取对应高度

int width = getWidth(); // 获取对应宽度

int singleHeight = height / b.length;// 获取每一个字母的高度

for (int i = 0; i < b.length; i++) {

if (!isInEditMode()) {

paint.setColor(Color.parseColor("#838383"));

}

paint.setAntiAlias(true);

paint.setTextSize(20);

// 选中的状态

if (i == choose) {

paint.setColor(getResources().getColor(R.color.yellow_light));

paint.setFakeBoldText(true);

}

// x坐标等于中间-字符串宽度的一半.

float xPos = width / 2 - paint.measureText(b[i]) / 2;

float yPos = singleHeight * i + singleHeight;

canvas.drawText(b[i], xPos, yPos, paint);

paint.reset();// 重置画笔

}

}

@SuppressWarnings("deprecation")

@Override

public boolean dispatchTouchEvent(MotionEvent event) {

final int action = event.getAction();

final float y = event.getY();// 点击y坐标

final int oldChoose = choose;

final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;

final int c = (int) (y / getHeight() * b.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.

switch (action) {

case MotionEvent.ACTION_UP:

setBackgroundDrawable(new ColorDrawable(0x00000000));

choose = -1;//

invalidate();

if (mTextDialog != null) {

mTextDialog.setVisibility(View.INVISIBLE);

}

break;

default:

if (oldChoose != c) {

if (c >= 0 && c < b.length) {

if (listener != null) {

listener.onTouchingLetterChanged(b[c]);

}

if (mTextDialog != null) {

mTextDialog.setText(b[c]);

mTextDialog.setVisibility(View.VISIBLE);

}

choose = c;

invalidate();

}

}

break;

}

return true;

}

/**

* 向外公开的方法

*

* @param onTouchingLetterChangedListener

*/

public void setOnTouchingLetterChangedListener(OnTouchingLetterChangedListener onTouchingLetterChangedListener) {

this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;

}

/**

* 接口

*

* @author coder

*

*/

public interface OnTouchingLetterChangedListener {

public void onTouchingLetterChanged(String s);

}

}

再次说明一边,需要的资源文件都是放在res下drawable -hdp里面的

下面我们就来实现功能,那么这个时候我们还需要什么呢,我们还需要一个dto,还有一个拼音库的jar包,jar包我也放在我的项目源代码里了,需要的一会自己下载完成的代码,这是我的项目文件存放位置

dto

package com.mulu.dto;

public class PersonDto {

private Integer userId;// 用户ID

private String name;// 姓名

private String head;// 头像

private String utype;// 用户类型

private String sortLetters; // 显示数据拼音的首字母

private String suoxie;// 姓名缩写

private String signature;// 个性签名

public final Integer getUserId() {

return userId;

}

public final void setUserId(Integer userId) {

this.userId = userId;

}

public final String getName() {

return name;

}

public final void setName(String name) {

this.name = name;

}

public final String getHead() {

return head;

}

public final void setHead(String head) {

this.head = head;

}

public final String getUtype() {

return utype;

}

public final void setUtype(String utype) {

this.utype = utype;

}

public final String getSortLetters() {

return sortLetters;

}

public final void setSortLetters(String sortLetters) {

this.sortLetters = sortLetters;

}

public final String getSuoxie() {

return suoxie;

}

public final void setSuoxie(String suoxie) {

this.suoxie = suoxie;

}

public final String getSignature() {

return signature;

}

public final void setSignature(String signature) {

this.signature = signature;

}

}

下面来看一下主文件中的代码吧

package com.mulu.activity;

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;

import android.app.Activity;

import android.os.Bundle;

import android.text.Editable;

import android.text.TextUtils;

import android.text.TextWatcher;

import android.widget.EditText;

import android.widget.ListView;

import android.widget.TextView;

import com.mulu.adapter.SchoolFriendMemberListAdapter;

import com.mulu.dto.PersonDto;

import com.mulu.widget.CharacterParser;

import com.mulu.widget.PinyinComparator;

import com.mulu.widget.SideBar;

public class MainActivity extends Activity implements SideBar.OnTouchingLetterChangedListener, TextWatcher {

private SideBar mSideBar;

private TextView mDialog;

private ListView mListView;

private EditText mSearchInput;

private CharacterParser characterParser;// 汉字转拼音

private PinyinComparator pinyinComparator;// 根据拼音来排列ListView里面的数据类

private List<PersonDto> sortDataList = new ArrayList<PersonDto>();

private SchoolFriendMemberListAdapter mAdapter;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mListView = (ListView) findViewById(R.id.school_friend_member);

mSideBar = (SideBar) findViewById(R.id.school_friend_sidrbar);

mDialog = (TextView) findViewById(R.id.school_friend_dialog);

mSearchInput = (EditText) findViewById(R.id.school_friend_member_search_input);

mSideBar.setTextView(mDialog);

mSideBar.setOnTouchingLetterChangedListener(this);

initData();

}

/**

* 初始化数据

*/

private void initData() {

// 实例化汉字转拼音类

characterParser = CharacterParser.getInstance();

pinyinComparator = new PinyinComparator();

PersonDto cuser1 = new PersonDto();

cuser1.setName("阿东");

cuser1.setSortLetters("a");

PersonDto cuser2 = new PersonDto();

cuser2.setName("贝贝");

cuser2.setSortLetters("b");

PersonDto cuser3 = new PersonDto();

cuser3.setName("西西");

cuser3.setSortLetters("x");

PersonDto cuser4 = new PersonDto();

cuser4.setName("楠楠");

cuser4.setSortLetters("n");

PersonDto cuser5 = new PersonDto();

cuser5.setName("君君");

cuser5.setSortLetters("j");

PersonDto cuser6 = new PersonDto();

cuser6.setName("陈诚");

cuser6.setSortLetters("c");

PersonDto cuser7 = new PersonDto();

cuser7.setName("美美");

cuser7.setSortLetters("m");

PersonDto cuser8 = new PersonDto();

cuser8.setName("花园");

cuser8.setSortLetters("h");

PersonDto cuser9 = new PersonDto();

cuser9.setName("天天");

cuser9.setSortLetters("t");

PersonDto cuser10 = new PersonDto();

cuser10.setName("八戒");

cuser10.setSortLetters("b");

sortDataList.add(cuser1);

sortDataList.add(cuser2);

sortDataList.add(cuser3);

sortDataList.add(cuser4);

sortDataList.add(cuser5);

sortDataList.add(cuser6);

sortDataList.add(cuser7);

sortDataList.add(cuser8);

sortDataList.add(cuser9);

sortDataList.add(cuser10);

fillData(sortDataList);

// 根据a-z进行排序源数据

Collections.sort(sortDataList, pinyinComparator);

mAdapter = new SchoolFriendMemberListAdapter(this, sortDataList);

mListView.setAdapter(mAdapter);

mSearchInput.addTextChangedListener(this);

}

@Override

public void onTouchingLetterChanged(String s) {

int position = 0;

// 该字母首次出现的位置

if(mAdapter != null){

position = mAdapter.getPositionForSection(s.charAt(0));

}

if (position != -1) {

mListView.setSelection(position);

}

}

@Override

public void onTextChanged(CharSequence s, int start, int before, int count) {

// 当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表

filterData(s.toString(), sortDataList);

}

@Override

public void afterTextChanged(Editable s) {

}

@Override

public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

/**

* 根据输入框中的值来过滤数据并更新ListView

*

* @param filterStr

*/

private void filterData(String filterStr, List<PersonDto> list) {

List<PersonDto> filterDateList = new ArrayList<PersonDto>();

if (TextUtils.isEmpty(filterStr)) {

filterDateList = list;

} else {

filterDateList.clear();

for (PersonDto sortModel : list) {

String name = sortModel.getName();

String suoxie = sortModel.getSuoxie();

if (name.indexOf(filterStr.toString()) != -1 || suoxie.indexOf(filterStr.toString()) != -1 || characterParser.getSelling(name).startsWith(filterStr.toString())) {

filterDateList.add(sortModel);

}

}

}

// 根据a-z进行排序

Collections.sort(filterDateList, pinyinComparator);

mAdapter.updateListView(filterDateList);

}

/**

* 填充数据

*

* @param list

*/

private void fillData(List<PersonDto> list) {

for (PersonDto cUserInfoDto : list) {

if (cUserInfoDto != null && cUserInfoDto.getName() != null) {

String pinyin = characterParser.getSelling(cUserInfoDto.getName());

String suoxie = CharacterParser.getFirstSpell(cUserInfoDto.getName());

cUserInfoDto.setSuoxie(suoxie);

String sortString = pinyin.substring(0, 1).toUpperCase();

if ("1".equals(cUserInfoDto.getUtype())) {// 判断是否是管理员

cUserInfoDto.setSortLetters("☆");

} else if (sortString.matches("[A-Z]")) {// 正则表达式,判断首字母是否是英文字母

cUserInfoDto.setSortLetters(sortString);

} else {

cUserInfoDto.setSortLetters("#");

}

}

}

}

}

这里还需要一个展示listView的一个适配器,我把它单独拿出来了,放在adapter包中的

package com.mulu.adapter;

import android.app.Activity;

import android.content.Context;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.*;

import com.mulu.dto.PersonDto;

import com.mulu.activity.R;

import java.util.List;

/**

* 成员列表适配器

*/

public class SchoolFriendMemberListAdapter extends BaseAdapter implements SectionIndexer {

private LayoutInflater inflater;

private Activity mActivity;

private List<PersonDto> list;

public SchoolFriendMemberListAdapter(Activity mActivity, List<PersonDto> list) {

this.mActivity = mActivity;

this.list = list;

}

/**

* 当ListView数据发生变化时,调用此方法来更新ListView

*

* @param list

*/

public void updateListView(List<PersonDto> list) {

this.list = list;

notifyDataSetChanged();

}

@Override

public int getCount() {

return list.size();

}

@Override

public Object getItem(int position) {

return null;

}

@Override

public long getItemId(int position) {

return position;

}

@Override

public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder holder = null;

if (convertView == null) {

inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

convertView = inflater.inflate(R.layout.items_person_list, null);

holder = new ViewHolder();

holder.ivHead = (ImageView) convertView.findViewById(R.id.head);

holder.tvTitle = (TextView) convertView.findViewById(R.id.title);

holder.tvLetter = (TextView) convertView.findViewById(R.id.catalog);

holder.tvLine = (TextView) convertView.findViewById(R.id.line);

holder.tvContent = (LinearLayout) convertView.findViewById(R.id.content);

convertView.setTag(holder);

} else {

holder = (ViewHolder) convertView.getTag();

}

final PersonDto dto = list.get(position);

if (dto != null) {

// 根据position获取分类的首字母的Char ascii值

int section = getSectionForPosition(position);

// 如果当前位置等于该分类首字母的Char的位置 ,则认为是第一次出现

if (position == getPositionForSection(section)) {

holder.tvLetter.setVisibility(View.VISIBLE);

holder.tvLetter.setText("☆".equals(dto.getSortLetters()) ? dto.getSortLetters() + "(管理员)" : dto.getSortLetters());

holder.tvLine.setVisibility(View.VISIBLE);

} else {

holder.tvLetter.setVisibility(View.GONE);

holder.tvLine.setVisibility(View.GONE);

}

holder.tvTitle.setText(dto.getName());

}

return convertView;

}

class ViewHolder {

ImageView ivHead;

TextView tvLetter;

TextView tvTitle;

TextView tvLine;

LinearLayout tvContent;

}

/**

* 根据ListView的当前位置获取分类的首字母的Char ascii值

*/

public int getSectionForPosition(int position) {

return list.get(position).getSortLetters().charAt(0);

}

/**

* 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置

*/

public int getPositionForSection(int section) {

for (int i = 0; i < getCount(); i++) {

String sortStr = list.get(i).getSortLetters();

char firstChar = sortStr.toUpperCase().charAt(0);

if (firstChar == section) {

return i;

}

}

return -1;

}

@Override

public Object[] getSections() {

return null;

}

}

还需要一个PinyinComparator实现Comparator的类

package com.mulu.widget;

import com.mulu.dto.PersonDto;

import java.util.Comparator;

public class PinyinComparator implements Comparator<PersonDto> {

@Override

public int compare(PersonDto o1, PersonDto o2) {

if (o1.getSortLetters().equals("☆")) {

return -1;

} else if (o2.getSortLetters().equals("☆")) {

return 1;

} else if (o1.getSortLetters().equals("#")) {

return -1;

} else if (o2.getSortLetters().equals("#")) {

return 1;

} else {

return o1.getSortLetters().compareTo(o2.getSortLetters());

}

}

}

好了基本的代码也就这些了,下面是我完整代码的地址,欢迎下载http://download.csdn.net/detail/shaozucheng/8204905

时间: 2024-10-11 07:08:27

类似于微信通讯录的界面Demo的相关文章

【iOS基础控件 - 11】【Demo】模仿qq ,微信 UI 聊天界面

A.需求 做出一个类似于QQ.微信的聊天界面 1.每个cell包含发送时间.发送人(头像).发送信息 2.使用对方头像放在左边,我方头像在右边 3.对方信息使用白色背景对话框,我方信息使用蓝色背景对话框 4.隐藏相同的发送时间 5.底部功能按钮:语音按钮.消息输入框.表情按钮.附加按钮 6.响应键盘事件,呼出键盘.隐藏键盘时对上述的视图作出上移操作 7.键盘的发送事件处理 Code Source: B.实现点 1.底层视图搭建 上部分聊天信息框:UITableView 下部分功能区:UIButt

【Android 仿微信通讯录 导航分组列表-上】使用ItemDecoration为RecyclerView打造带悬停头部的分组列表

[Android 仿微信通讯录 导航分组列表-上]使用ItemDecoration为RecyclerView打造带悬停头部的分组列表 一 概述 本文是Android导航分组列表系列上,因时间和篇幅原因分上下,最终上下合璧,完整版效果如下: 上部残卷效果如下:两个ItemDecoration,一个实现悬停头部分组列表功能,一个实现分割线(官方demo) 网上关于实现带悬停分组头部的列表的方法有很多,像我看过有主席的自定义ExpandListView实现的,也看过有人用一个额外的父布局里面套 Rec

[iOS基础控件 - 6.9] 聊天界面Demo

A.需求 做出一个类似于QQ.微信的聊天界面 1.每个cell包含发送时间.发送人(头像).发送信息 2.使用对方头像放在左边,我方头像在右边 3.对方信息使用白色背景对话框,我方信息使用蓝色背景对话框 4.隐藏相同的发送时间 5.底部功能按钮:语音按钮.消息输入框.表情按钮.附加按钮 6.响应键盘事件,呼出键盘.隐藏键盘时对上述的视图作出上移操作 7.键盘的发送事件处理 B.实现点 1.底层视图搭建 上部分聊天信息框:UITableView 下部分功能区:UIButton 信息输入框使用无边框

iOS 裁剪圆形图像并显示(类似于微信头像)

本文主要讲解如何从照片库选择一张照片后将其裁剪成圆形头像并显示,类似于微信头像那种模式. 本文的方法也适用于当时拍照获取的图像,方法类似,所以不再赘述. 本文主要是在iOS 10环境下使用,此时如果要使用使用系统照片库.照相机等功能需要授权,授权方法如下: 右键点击工程目录中的"Info.plist文件-->Open As -->Source Code",打开复制以下你在应用中使用的隐私权限设置(描述自己修改): <key>NSVideoSubscriberAc

运用BeautyEye组件开发Swing登录界面Demo

import org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper; import org.jb2011.lnf.beautyeye.ch3_button.BEButtonUI; import org.jb2011.lnf.beautyeye.ch8_toolbar.BEToolBarUI; import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListen

Android 仿微信QQ聊天界面

一些IM聊天软件的展现形式是左右分开的形式.比如说,别人给你发的信息全部靠左显示,你自己发给别人的信息全部靠右显示. 而我们的ListView很多时候是显示同一个布局,其实BaseAdapter中有2个重要的方法在大多数情况下我们并未使用到,一个是public int getViewTypeCount(),显示ListView中有多少种布局(默认是显示是1),像微信那样聊天界面,是有2种布局方式:另外一个getItemViewType(),可以让不同item条目加载不同的布局,下面就简单的模拟下

Android微信分享功能实例+demo

Android微信分享功能实例 1 微信开放平台注册 2 获得appId,添加到程序中,并运行程序 3 使用应用签名apk生成签名,添加到微信开放平台应用签名,完成注册 4 测试分享功能. 有问题请留言  o(∩_∩)o 哈哈 代码如下: package com.wx; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.View; import a

Android仿微信语音聊天界面

有段时间没有看视频了,昨天晚上抽了点空时间,又看了下鸿洋大神的视频教程,又抽时间写了个学习记录.代码和老师讲的基本一样,网上也有很多相同的博客.我只是在AndroidStudio环境下写的. --主界面代码-- public class MainActivity extends Activity { private ListView mListView; private ArrayAdapter<Recorder> mAdapter; private List<Recorder>

通过SectionIndexer实现微信通讯录

这里主要参考了使用SectionIndexer实现微信通讯录的效果 在这里做个记录 效果图 页面使用RelativeLayout,主要分为三个部分,match_parent的主listView,右边字母的SideBar,还有就是微信那种点击字母时浮动的一个TextView 布局: fragment_contacts.xml 1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmln