项目要求
- 使用RecyclerView实现一个微信通讯录
设计效果
- 垂直item列表
- 按姓名首字母排序
- 根据右侧首字母bar快速查找
- 左滑删除联系人
效果演示
项目结构
实现思路
- 添加支持库打开应用模块的 build.gradle 文件dependencies 部分
dependencies {
implementation 'com.android.support:recyclerview-v7:28.0.0'
}
- 将 RecyclerView 添加到布局中
- 添加列表适配器RecyclerView.Adapter
- 调用适配器的 onCreateViewHolder() 方法
- 为列表项添加动画
- 根据网络上已有的demo将activity修改移植进wechat已有的fragment中
遇到的困难
网络上的实例是一个完整的activity,尝试过把Activity嵌入到现有的Fragment中行不通,因为Fragment依赖于父Activity而存在,不能本末倒置。
后来采用的方法是直接将demo Activity修改成Fragment
这里需要注意几点:
- 在Fragment里面的onCreate()函数内,是没有办法使用findViewById、setContentView这些函数的。因为Fragment本身并没有提供这些方法。于是我们只能通过onCreateView和onViewCreated来实现对显示的控制
- 布局通过inflate
将this替换为this.getActivity()
将findViewById替换为view.findViewById - onCreateView的作用是返回一个view
- onViewCreated的作用是进行Fragment的初始化动作
- 原本的demo中重载了onCreateOptionsMenu函数来显示选项卡,但Fragment中不支持它故将其删除,解决方法是将其放入MainActivity中重载
代码示例
Frd_Fragment
public class Frd_Fragment extends Fragment {
ContactModel mModel;
private SideBar mSideBar;
private ZSideBar mZSideBar;
private TextView mUserDialog;
private TouchableRecyclerView mRecyclerView;
private List<ContactModel.MembersEntity> mMembers = new ArrayList<>();
private CharacterParser characterParser;
private PinyinComparator pinyinComparator;
private ContactAdapter mAdapter;
private List<ContactModel.MembersEntity> mAllLists = new ArrayList<>();
private int mPermission;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.tab02, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getPermission();
initView(view);
}
private void initView(View view) {
characterParser = CharacterParser.getInstance();
pinyinComparator = new PinyinComparator();
mSideBar = (SideBar) view.findViewById(R.id.contact_sidebar);
mZSideBar = (ZSideBar) view.findViewById(R.id.contact_zsidebar);
mUserDialog = (TextView) view.findViewById(R.id.contact_dialog);
mRecyclerView = (TouchableRecyclerView) view.findViewById(R.id.contact_member);
mSideBar.setTextView(mUserDialog);
// fillData();
getNetData(0);
}
private void getPermission() {
mPermission = CommonString.PermissionCode.TEACHER;
}
public void getNetData(final int type) {
//id 已经被处理过
String tempData = "{\"groupName\":\"中国\",\"admins\":[{\"id\":\"111221\",\"username\":\"程景瑞\",\"profession\":\"teacher\"},{\"id\":\"bfcd1feb5db2\",\"username\":\"钱黛\",\"profession\":\"teacher\"},{\"id\":\"bfcd1feb5db2\",\"username\":\"许勤颖\",\"profession\":\"teacher\"},{\"id\":\"bfcd1feb5db2\",\"username\":\"孙顺元\",\"profession\":\"teacher\"},{\"id\":\"fcd1feb5db2\",\"username\":\"朱佳\",\"profession\":\"teacher\"},{\"id\":\"bfcd1feb5db2\",\"username\":\"李茂\",\"profession\":\"teacher\"},{\"id\":\"d1feb5db2\",\"username\":\"周莺\",\"profession\":\"teacher\"},{\"id\":\"cd1feb5db2\",\"username\":\"任倩栋\",\"profession\":\"teacher\"},{\"id\":\"d1feb5db2\",\"username\":\"严庆佳\",\"profession\":\"teacher\"}],\"members\":[{\"id\":\"d1feb5db2\",\"username\":\"彭怡1\",\"profession\":\"student\"},{\"id\":\"d1feb5db2\",\"username\":\"方谦\",\"profession\":\"student\"},{\"id\":\"dd2feb5db2\",\"username\":\"谢鸣瑾\",\"profession\":\"student\"},{\"id\":\"dd2478fb5db2\",\"username\":\"孔秋\",\"profession\":\"student\"},{\"id\":\"dd24cd1feb5db2\",\"username\":\"曹莺安\",\"profession\":\"student\"},{\"id\":\"dd2478eb5db2\",\"username\":\"酆有松\",\"profession\":\"student\"},{\"id\":\"dd2478b5db2\",\"username\":\"姜莺岩\",\"profession\":\"student\"},{\"id\":\"dd2eb5db2\",\"username\":\"谢之轮\",\"profession\":\"student\"},{\"id\":\"dd2eb5db2\",\"username\":\"钱固茂\",\"profession\":\"student\"},{\"id\":\"dd2d1feb5db2\",\"username\":\"潘浩\",\"profession\":\"student\"},{\"id\":\"dd24ab5db2\",\"username\":\"花裕彪\",\"profession\":\"student\"},{\"id\":\"dd24ab5db2\",\"username\":\"史厚婉\",\"profession\":\"student\"},{\"id\":\"dd24a00d1feb5db2\",\"username\":\"陶信勤\",\"profession\":\"student\"},{\"id\":\"dd24a5db2\",\"username\":\"水天固\",\"profession\":\"student\"},{\"id\":\"dd24a5db2\",\"username\":\"柳莎婷\",\"profession\":\"student\"},{\"id\":\"dd2d1feb5db2\",\"username\":\"冯茜\",\"profession\":\"student\"},{\"id\":\"dd24a0eb5db2\",\"username\":\"吕言栋\",\"profession\":\"student\"}],\"creater\":{\"id\":\"1\",\"username\":\"褚奇清\",\"profession\":\"teacher\"}}";
try {
Gson gson = new GsonBuilder().create();
mModel = gson.fromJson(tempData, ContactModel.class);
setUI();
} catch (Exception e) {
}
}
private void setUI() {
mSideBar.setOnTouchingLetterChangedListener(new SideBar.OnTouchingLetterChangedListener() {
@Override
public void onTouchingLetterChanged(String s) {
if (mAdapter != null) {
mAdapter.closeOpenedSwipeItemLayoutWithAnim();
}
int position = mAdapter.getPositionForSection(s.charAt(0));
if (position != -1) {
mRecyclerView.getLayoutManager().scrollToPosition(position);
}
}
});
seperateLists(mModel);
if (mAdapter == null) {
mAdapter = new ContactAdapter(this.getActivity(), mAllLists, mPermission, mModel.getCreater().getId(), new OneBack() {
@Override
public void deleteUser(int position) {
delUser(position);
}
});
int orientation = LinearLayoutManager.VERTICAL;
final LinearLayoutManager layoutManager = new LinearLayoutManager(this.getActivity(), orientation, false);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(mAdapter);
final StickyRecyclerHeadersDecoration headersDecor = new StickyRecyclerHeadersDecoration(mAdapter);
mRecyclerView.addItemDecoration(headersDecor);
mRecyclerView.addItemDecoration(new DividerDecoration(this.getActivity()));
// setTouchHelper();
mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
headersDecor.invalidateHeaders();
}
});
} else {
mAdapter.notifyDataSetChanged();
}
mZSideBar.setupWithRecycler(mRecyclerView);
}
private void seperateLists(ContactModel mModel) {
//群主
ContactModel.CreaterEntity creatorEntity = mModel.getCreater();
ContactModel.MembersEntity tempMember = new ContactModel.MembersEntity();
tempMember.setUsername(creatorEntity.getUsername());
tempMember.setId(creatorEntity.getId());
tempMember.setProfession(creatorEntity.getProfession());
tempMember.setSortLetters("$");
mAllLists.add(tempMember);
//管理员
if (mModel.getAdmins() != null && mModel.getAdmins().size() > 0) {
for (ContactModel.AdminsEntity e : mModel.getAdmins()) {
ContactModel.MembersEntity eMember = new ContactModel.MembersEntity();
eMember.setSortLetters("%");
eMember.setProfession(e.getProfession());
eMember.setUsername(e.getUsername());
eMember.setId(e.getId());
mAllLists.add(eMember);
}
}
//members;
if (mModel.getMembers() != null && mModel.getMembers().size() > 0) {
for (int i = 0; i < mModel.getMembers().size(); i++) {
ContactModel.MembersEntity entity = new ContactModel.MembersEntity();
entity.setId(mModel.getMembers().get(i).getId());
entity.setUsername(mModel.getMembers().get(i).getUsername());
entity.setProfession(mModel.getMembers().get(i).getProfession());
String pinyin = characterParser.getSelling(mModel.getMembers().get(i).getUsername());
String sortString = pinyin.substring(0, 1).toUpperCase();
if (sortString.matches("[A-Z]")) {
entity.setSortLetters(sortString.toUpperCase());
} else {
entity.setSortLetters("#");
}
mMembers.add(entity);
}
Collections.sort(mMembers, pinyinComparator);
mAllLists.addAll(mMembers);
}
}
public void delUser(final int position) {
mAdapter.remove(mAdapter.getItem(position));
showToast("删除成功");
}
public void showToast(String value) {
Toast.makeText(this.getActivity(), value, Toast.LENGTH_SHORT).show();
}
}
tab02.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.example.widget.TouchableRecyclerView
android:id="@+id/contact_member"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:layout_marginRight="15dp" />
<TextView
android:id="@+id/contact_dialog"
android:layout_width="80.0dip"
android:layout_height="80.0dip"
android:layout_gravity="center"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:textColor="#ffffffff"
android:textSize="30.0dip"
android:visibility="invisible" />
<com.example.widget.SideBar
android:id="@+id/contact_sidebar"
android:layout_width="15dp"
android:layout_height="fill_parent"
android:layout_gravity="right|center"
android:layout_marginRight="3dp" />
<com.example.widget.ZSideBar
android:id="@+id/contact_zsidebar"
android:layout_width="24dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:visibility="gone" />
</FrameLayout>
</LinearLayout>
完整代码
码云仓库:我的码云仓库
鸣谢
github:jiang111:jiang111的github仓库