android 实现QQ好友列表

简介: 在某些Android开发群里,看到有些新手问怎么实现QQ好友列表,其实网上一搜挺多的。接触Android,也才一年的时间,大部分时间花在工作上(解bug。。。),界面上开发很少参与。自己维护的系统应用里,有个ExpandableListView的界面(其实android例子APIDemo也有类似的例子)就在这里写个Demo供新手参考。

在某些Android开发群里,看到有些新手问怎么实现QQ好友列表,其实网上一搜挺多的。接触Android,也才一年的时间,大部分时间花在工作上(解bug。。。),界面上开发很少参与。自己维护的系统应用里,有个ExpandableListView的界面(其实android例子APIDemo也有类似的例子)就在这里写个Demo供新手参考。        ExpandableListView的用法:难点就是重写BaseExpandableListAdapter及提供的数据源。

        下面看看继承BaseExpandableListAdapter的适配器:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<SPAN xmlns= "http://www.w3.org/1999/xhtml" > package com.xyz.expande;
  
import java.util.List;
  
import android.app.AlertDialog;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ImageView;
import android.widget.TextView;
  
public class ExpandAdapter extends BaseExpandableListAdapter {
  
    private Context mContext;
    private LayoutInflater mInflater = null ;
    private String[]   mGroupStrings = null ;
    private List<List<Item>>   mData = null ;
  
    public ExpandAdapter(Context ctx, List<List<Item>> list) {
         mContext = ctx;
         mInflater = (LayoutInflater) mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         mGroupStrings = mContext.getResources().getStringArray(R.array.groups);
         mData = list;
    }
  
    public void setData(List<List<Item>> list) {
         mData = list;
    }
  
    @Override
    public int getGroupCount() {
         // TODO Auto-generated method stub
         return mData.size();
    }
  
    @Override
    public int getChildrenCount( int groupPosition) {
         // TODO Auto-generated method stub
         return mData.get(groupPosition).size();
    }
  
    @Override
    public List<Item> getGroup( int groupPosition) {
         // TODO Auto-generated method stub
         return mData.get(groupPosition);
    }
  
    @Override
    public Item getChild( int groupPosition, int childPosition) {
         // TODO Auto-generated method stub
         return mData.get(groupPosition).get(childPosition);
    }
  
    @Override
    public long getGroupId( int groupPosition) {
         // TODO Auto-generated method stub
         return groupPosition;
    }
  
    @Override
    public long getChildId( int groupPosition, int childPosition) {
         // TODO Auto-generated method stub
         return childPosition;
    }
  
    @Override
    public boolean hasStableIds() {
         // TODO Auto-generated method stub
         return false ;
    }
  
    @Override
    public View getGroupView( int groupPosition, boolean isExpanded,
             View convertView, ViewGroup parent) {
         // TODO Auto-generated method stub
         if (convertView == null ) {
             convertView = mInflater.inflate(R.layout.group_item_layout, null );
         }
         GroupViewHolder holder = new GroupViewHolder();
         holder.mGroupName = (TextView) convertView
                .findViewById(R.id.group_name);
         holder.mGroupName.setText(mGroupStrings[groupPosition]);
         holder.mGroupCount = (TextView) convertView
                .findViewById(R.id.group_count);
         holder.mGroupCount.setText( "[" + mData.get(groupPosition).size() + "]" );
         return convertView;
    }
  
    @Override
    public View getChildView( int groupPosition, int childPosition,
             boolean isLastChild, View convertView, ViewGroup parent) {
         // TODO Auto-generated method stub
         if (convertView == null ) {
             convertView = mInflater.inflate(R.layout.child_item_layout, null );
         }
         ChildViewHolder holder = new ChildViewHolder();
         holder.mIcon = (ImageView) convertView.findViewById(R.id.img);
         holder.mIcon.setBackgroundResource(getChild(groupPosition,
                childPosition).getImageId());
         holder.mChildName = (TextView) convertView.findViewById(R.id.item_name);
         holder.mChildName.setText(getChild(groupPosition, childPosition)
                .getName());
         holder.mDetail = (TextView) convertView.findViewById(R.id.item_detail);
         holder.mDetail.setText(getChild(groupPosition, childPosition)
                .getDetail());
         return convertView;
    }
  
    @Override
    public boolean isChildSelectable( int groupPosition, int childPosition) {
         // TODO Auto-generated method stub
         <SPAN style= "COLOR: #cc0000" > /*很重要:实现ChildView点击事件,必须返回true*/
</SPAN>         return true ;
    }
  
    private class GroupViewHolder {
         TextView mGroupName;
         TextView mGroupCount;
    }
  
    private class ChildViewHolder {
         ImageView mIcon;
         TextView mChildName;
  
</LinearLayout></SPAN></SPAN>


        TextView mDetail;
    }

}
</SPAN>[/mw_shl_code]

里面用到的有两个布局,GroupView(子list没展开的view)如图:  
<IGNORE_JS_OP>




布局group_item_layout.xml如下:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<SPAN xmlns= "http://www.w3.org/1999/xhtml" ><SPAN xmlns= "http://www.w3.org/1999/xhtml" ><?xml version= "1.0" encoding= "utf-8" ?>
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
    android:layout_width= "match_parent"
    android:layout_height= "?android:attr/listPreferredItemHeight"
    android:orientation= "horizontal" >
  
    <TextView
         android:id= "@+id/group_name"
         android:layout_width= "wrap_content"
         android:layout_height= "?android:attr/listPreferredItemHeight"
         android:textAppearance= "?android:attr/textAppearanceMedium"
         android:layout_marginLeft= "35dip"
         android:gravity= "center_vertical"
         android:singleLine= "true" />
  
    <TextView
         android:id= "@+id/group_count"
         android:layout_width= "wrap_content"
         android:layout_height= "?android:attr/listPreferredItemHeight"
         android:textAppearance= "?android:attr/textAppearanceMedium"
         android:layout_marginLeft= "5dip"
         android:gravity= "center_vertical"
         android:singleLine= "true" />
  
</LinearLayout></SPAN></SPAN>



另外一个就是ChildView,本例仿QQ好友列表,如图:
<IGNORE_JS_OP>




布局child_item_layout.xml如下:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<SPAN xmlns= "http://www.w3.org/1999/xhtml" ><SPAN xmlns= "http://www.w3.org/1999/xhtml" ><?xml version= "1.0" encoding= "utf-8" ?>
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
    android:layout_width= "fill_parent"
    android:layout_height= "wrap_content"
    android:minHeight= "@dimen/min_Height"
    <SPAN style= "COLOR: #ff0000" >android:descendantFocusability= "blocksDescendants"
</SPAN>    android:orientation= "horizontal" >
  
    <ImageButton
         android:id= "@+id/img"
         android:layout_width= "@dimen/image_width"
         android:layout_height= "@dimen/image_width"
         android:layout_marginLeft= "2dip"
         android:layout_marginRight= "10dip"
         android:layout_gravity= "center_vertical" />
  
    <LinearLayout
         android:layout_width= "wrap_content"
         android:layout_height= "match_parent"
         android:descendantFocusability= "blocksDescendants"
         android:orientation= "vertical" >
  
         <TextView
             android:id= "@+id/item_name"
             android:layout_width= "wrap_content"
             android:layout_height= "0.0dip"
             android:gravity= "center_vertical"
             android:layout_weight= "1" />
  
         <TextView
             android:id= "@+id/item_detail"
             android:layout_width= "wrap_content"
             android:layout_height= "0.0dip"
             android:gravity= "center_vertical"
             android:singleLine= "true"
             android:ellipsize= "end"
             android:layout_weight= "1" />
          
    </LinearLayout>
  
</LinearLayout></SPAN></SPAN>




适配器弄好了,ExpandableListView就用系统的,现在只剩下显示的问题啦

先来几张效果图:

<IGNORE_JS_OP>

    <IGNORE_JS_OP>



<IGNORE_JS_OP>

   <IGNORE_JS_OP>



主Activity如下:

onChildClick

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
<SPAN xmlns= "http://www.w3.org/1999/xhtml" ><SPAN xmlns= "http://www.w3.org/1999/xhtml" > package com.xyz.expande;
  
import java.util.ArrayList;
import java.util.List;
  
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.ExpandableListView;
import android.widget.ExpandableListView.OnChildClickListener;
  
public class HomeActivity extends Activity implements OnChildClickListener {
  
    private ExpandableListView mListView = null ;
    private ExpandAdapter mAdapter = null ;
    private List<List<Item>> mData = new ArrayList<List<Item>>();
  
    private int [] mGroupArrays = new int [] { 
             R.array.tianlongbabu,
             R.array.shediaoyingxiongzhuan, 
             R.array.shendiaoxialv };
  
    private int [] mDetailIds = new int [] { 
             R.array.tianlongbabu_detail,
             R.array.shediaoyingxiongzhuan_detail, 
             R.array.shendiaoxialv_detail };
  
    private int [][] mImageIds = new int [][] {
             { R.drawable.img_00, 
               R.drawable.img_01, 
               R.drawable.img_02 },
             { R.drawable.img_10, 
               R.drawable.img_11, 
               R.drawable.img_12,
               R.drawable.img_13, 
               R.drawable.img_14, 
               R.drawable.img_15,
               R.drawable.img_16 },
             { R.drawable.img_20,
               R.drawable.img_21 } };
  
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         initData();
         mListView = new ExpandableListView( this );
         mListView.setLayoutParams( new LayoutParams(LayoutParams.FILL_PARENT,
                LayoutParams.FILL_PARENT));
         setContentView(mListView);
          
         mListView.setGroupIndicator(getResources().getDrawable(
                R.drawable.expander_floder));
         mAdapter = new ExpandAdapter( this , mData);
         mListView.setAdapter(mAdapter);
         mListView
                .setDescendantFocusability(ExpandableListView.FOCUS_AFTER_DESCENDANTS);
         mListView.setOnChildClickListener( this );
    }
  
    <SPAN style= "COLOR: #ff0000" > /*
      * ChildView 设置 布局很可能onChildClick进不来,要在 ChildView layout 里加上
      * android:descendantFocusability="blocksDescendants",
      * 还有isChildSelectable里返回true
      */
</SPAN>    @Override
    public boolean onChildClick(ExpandableListView parent, View v,
             int groupPosition, int childPosition, long id) {
         // TODO Auto-generated method stub
         Item item = mAdapter.getChild(groupPosition, childPosition);
         new AlertDialog.Builder( this )
                .setTitle(item.getName())
                .setMessage(item.getDetail())
                .setIcon(android.R.drawable.ic_menu_more)
                .setNegativeButton(android.R.string.cancel,
                         new OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog,
                                     int which) {
                                 // TODO Auto-generated method stub
  
                            }
                         }).create().show();
         return true ;
    }
  
    private void initData() {
         for ( int i = 0 ; i < mGroupArrays.length; i++) {
             List<Item> list = new ArrayList<Item>();
             String[] childs = getStringArray(mGroupArrays<I>);
             String[] details = getStringArray(mDetailIds<I>);
             for ( int j = 0 ; j < childs.length; j++) {
                Item item = new Item(mImageIds<I>[j], childs[j], details[j]);
                list.add(item);
             }
             mData.add(list);
         }
    }
  
    private String[] getStringArray( int resId) {
         return getResources().getStringArray(resId);
    }
  
}</SPAN></SPAN>




这这个demo的时候,想实现ChildView的点击事件,实现接口onChildClick,发现不进来,很尴尬。。。最后还是在网上找到答案了,第一,在适配器里isChildSelectable 必须返回true,第二,ChildView布局child_item_layout.xml最外层的layout设置个属性

细心的同学会发现 Item 是啥?也贴出来吧

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.xyz.expande;
  
public class Item {
      
    private int resId;
    private String name;
    private String detail;
      
    public Item( int resId, String name, String detail) {
         this .resId  = resId;
         this .name   = name;
         this .detail = detail;
    }
      
    public void setImageId( int resId) {
         this .resId  = resId;
    }
      
    public int getImageId() {
         return resId;
    }
      
    public void setName(String name) {
         this .name   = name;
    }
      
    public String getName() {
         return name;
    }
      
    public void setDetail(String detail) {
         this .detail = detail;
    }
      
    public String getDetail() {
         return detail;
    }
      
    public String toString() {
         return "Item[" + resId + ", " + name + ", " + detail + "]" ;
    }
  
}



源码下载: <IGNORE_JS_OP>ExpandeList.zip (670.11 KB, 下载次数: 988)

http://www.eoeandroid.com/forum.php?mod=misc&action=attachcredit&aid=81469&formhash=2f2ef89c

原文:http://blog.csdn.net/zhouyuanjing/article/details/8254421

目录
相关文章
|
13天前
|
Dart 前端开发 Android开发
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
37 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
2月前
|
存储 监控 API
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
app开发之安卓Android+苹果ios打包所有权限对应解释列表【长期更新】-以及默认打包自动添加权限列表和简化后的基本打包权限列表以uniapp为例-优雅草央千澈
90 11
|
8月前
|
存储 数据库 Android开发
安卓Jetpack Compose+Kotlin,支持从本地添加音频文件到播放列表,支持删除,使用ExoPlayer播放音乐
为了在UI界面添加用于添加和删除本地音乐文件的按钮,以及相关的播放功能,你需要实现以下几个步骤: 1. **集成用户选择本地音乐**:允许用户从设备中选择音乐文件。 2. **创建UI按钮**:在界面中创建添加和删除按钮。 3. **数据库功能**:使用Room数据库来存储音频文件信息。 4. **更新ViewModel**:处理添加、删除和播放音频文件的逻辑。 5. **UI实现**:在UI层支持添加、删除音乐以及播放功能。
|
6月前
|
Android开发 开发者 UED
Android项目架构设计问题之加载数据到列表如何解决
Android项目架构设计问题之加载数据到列表如何解决
51 0
|
8月前
|
存储 API Android开发
29. 【Android教程】折叠列表 ExpandableListView
29. 【Android教程】折叠列表 ExpandableListView
645 2
|
8月前
|
前端开发 API Android开发
25. 【Android教程】列表控件 ListView
25. 【Android教程】列表控件 ListView
288 2
|
9月前
|
Android开发
Android获取蓝牙设备列表的方法
Android获取蓝牙设备列表的方法
615 5
|
8月前
|
安全 Java API
Android获取Wi-Fi网络列表
【6月更文挑战第21天】
139 0
|
9月前
|
Android开发
Android 获取 USB设备列表
Android 获取 USB设备列表 【5月更文挑战第6天】
326 4
|
9月前
|
存储 缓存 Android开发
构建高效的Android应用:采用RecyclerView优化列表显示
【4月更文挑战第2天】 在移动开发领域,列表显示是最常见的用户界面组件之一。对于Android平台而言,RecyclerView因其高效、灵活的特点而备受开发者青睐。本文将深入探讨如何利用RecyclerView在Android应用中实现流畅的列表滚动,以及通过各种优化策略来提升性能和用户体验。我们将从基本概念出发,逐步展开如何自定义适配器、视图持有者,以及利用布局管理器来实现复杂的列表布局。此外,还将讨论如何通过异步加载、缓存机制和动态数据更新来进一步优化性能。
121 1

热门文章

最新文章

  • 1
    如何修复 Android 和 Windows 不支持视频编解码器的问题?
  • 2
    Android历史版本与APK文件结构
  • 3
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 4
    【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
  • 5
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
  • 6
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
  • 7
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 8
    Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
  • 9
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 10
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 1
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    24
  • 2
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    32
  • 3
    Android历史版本与APK文件结构
    120
  • 4
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    27
  • 5
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    23
  • 6
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
    56
  • 7
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    37
  • 8
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
    73
  • 9
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    117
  • 10
    Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
    29