2.19 Android Diary
1 AppExplorer 软件管理器实现思路: 2 3 (学习ZhengPing老师的软件管理器的开发教程后的内容整理) 4 5 1、需求: 6 软件管理器界面全屏,加载过程中有与用户交互的信息, 7 软件的排列方式有网格方式和列表方式两种,展现出的软件类型有 8 用户软件和所有软件两种。可对每一个控件实现动画效果。 9 10 2、界面设计: 11 <1>AppExplorer的整体界面布局(show_app_grid.xml): 12 最上端显示title,中间部分显示软件,下方两个button分别用来对 13 软件展示方式和软件类型进行选择。整体使用相对布局的方式。 14 1) title部分包括一个ImageView和一个TextView,二者以线性布局 15 的方式排列。为了美观起见,对LinearLayout进行了paddingLeft设 16 置。(内边距) 17 2) 中间部分分列表方式和网格方式来排列软件,在使用其中一种 18 方式的时候,另一种设置visibility="Gone"即可。默认情况下以网 19 格方式展示软件,因此先设置ListView的visibility="invisible" 20 GridView: 21 android:numColumns="3" //列数设置为3 22 android:horizontalSpacing="10px" //水平列间距 23 android:verticalSpacing="10px" //垂直间距 24 android:listSelector="@drawable/choose_gridview" //被选定后的背景图片 25 ... 26 ListView: 27 ... 28 android:listSelector="@drawable/choose_listview" 29 android:visibility="invisible" //invisible不可见但是占空间,Gone消失后不占地空间 30 3) 下方在RelativeLayout中设置两个ImageButton供用户选择,分别 31 layout_alignParentRight和layout_alignParentLeft 32 <2>针对网格方式和列表方式两种效果,设计两个item的布局文件(lv_item.xml、gv_item.xml) 33 1)gv_item.xml: 34 因为网格模式下只需要显示软件的icon和软件名,所以用一个LinearLayout 35 存放一个ImageView和一个TextView即可 36 2)lv_item.xml: 37 列表模式下需要显示软件的icon、软件名、包名,整体用LinearLayout沿水平方向排列, 38 ImageView作为一项,两个TextView包含在一个LinearLayout中作为另一项 39 <3>美化: 40 为了实现全屏显示的效果,在MainActivity的OnCreate方法中添加语句: 41 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); 42 去除App自带的title 43 requestWindowFeature(Window.FEATURE_NO_TITLE); 44 45 3、程序部分: 46 <1> 设置布局文件 47 setContentView(R.layout.show_app_grid); 48 找出布局文件中的两个view 49 lv = (ListView)this.findViewById(R.id.lv_apps); 50 gv = (GridView)this.findViewById(R.id.gv_apps); 51 <2> 为每个view设置一个适配器 52 class GridViewAdapter extends BaseAdapter{ 53 LayoutInflater inflater; //用来寻找layout下xml布局文件并且将其实例化 54 List<PackageInfo> pkgInfos; 55 public GridViewAdapter(Context context,List<PackageInfo> packageInfos){ 56 inflater = LayoutInflater.from(context);//将xml文件转换为视图 57 this.pkgInfos = packageInfos; 58 //复写BaseAdapter的方法 59 public int getCount() { 60 return pkgInfos.size();//返回list的大小 61 ... 62 public View getView(int position, View convertView, ViewGroup parent) { 63 View view = inflater.inflate(R.layout.gv_item, null);//将布局文件渲染成view 64 //将show_app_grid中的view找出来 65 TextView tv =(TextView)view.findViewById(R.id.gv_item_appname); 66 ImageView iv = (ImageView)view.findViewById(R.id.gv_item_icon); 67 //给view中的控件赋值 68 tv.setText(pkgInfos.get(position).applicationInfo.loadLabel(getPackageManager())); 69 iv.setImageDrawable(pkgInfos.get(position).applicationInfo.loadIcon(getPackageManager())); 70 return view; 71 } 72 } 73 } 74 75 <3> 取出软件的packageInfo,区分出用户软件: 76 packageInfos = getPackageManager().getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_ACTIVITIES); 77 userPackageInfos = new ArrayList<PackageInfo>(); 78 for(int i=0;i<packageInfos.size();i++) { 79 PackageInfo temp = packageInfos.get(i); 80 ApplicationInfo appInfo = temp.applicationInfo; 81 boolean flag = false; 82 //flag为true时表示是用户程序 83 if((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0){ //Updated System app 84 flag = true; 85 }else if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) //Non-System app 86 flag = true; 87 if(flag) 88 userPackageInfos.add(temp); 89 } 90 91 <4> 在主函数中添加ProgressDialog,提高用户体验,使其在等待时看到下列的对话框 92 pd = ProgressDialog.show(this,"请稍后……","正在搜索你所安装的应用程序",true,false); 93 Thread t = new Thread(this); 94 t.start(); 95 在handler方法中,各个view的适配器设置完毕之后,添加: 96 pd.dismiss(); //将"正在加载"消息去除掉 97 98 <5> 为了提高效率,将查找安装软件的工作交给线程执行(添加到run方法中),执行完毕后 99 使用mHandler.sendEmptyMessage(0);向Handler发消息,用于不同线程间的消息传递 100 private Handler mHandler = new Handler(){ // 实现不同线程间消息的传递 101 @Override 102 public void handleMessage(Message msg) { 103 super.handleMessage(msg); 104 //当前对象是 mhandler,而这里需要的是activity对象所以强行指定this 105 showPackageInfos = packageInfos; 106 //在线程中设置适配器 107 gv.setAdapter(new GridViewAdapter(MainActivity.this,showPackageInfos)); 108 lv.setAdapter(new ListViewAdapter(MainActivity.this,showPackageInfos)); 109 } 110 }; 111 112 <6> 找出布局文件中的两个ImageButton 113 ib_change_category = (ImageButton) this.findViewById(R.id.ib_change_category); 114 ib_change_view = (ImageButton)this.findViewById(R.id.ib_change_view); 115 分别设置监听器 116 ib_change_category.setOnClickListener(new OnClickListener() { 117 @Override 118 public void onClick(View arg0) { 119 // TODO Auto-generated method stub 120 if(allApplication) { 121 ib_change_category.setImageResource(R.drawable.user);//改变图片 122 showPackageInfos = userPackageInfos; //如果展示的是所有程序,点击按钮会切换到用户程序 123 allApplication = false; 124 MyToast.MyToastShow(MainActivity.this, R.drawable.user,"用户程序",Toast.LENGTH_SHORT); 125 } 126 else 127 ... 128 //重新设置适配器,更新显示的情况 129 gv.setAdapter(new GridViewAdapter(MainActivity.this, showPackageInfos)); 130 lv.setAdapter(new ListViewAdapter(MainActivity.this, showPackageInfos)); 131 } 132 }); 133 ib_change_view.setOnClickListener(new OnClickListener() { 134 @Override 135 public void onClick(View v) { 136 // TODO Auto-generated method stub 137 lv.setAdapter(new ListViewAdapter(MainActivity.this, showPackageInfos)); 138 if(gridView) { 139 gridView = false; 140 gv.setVisibility(View.GONE);//如果显示的是Gridview,点击按钮会让它消失且不占地方 141 lv.setVisibility(View.VISIBLE);//原本设置为invisible的ListView变得可见了 142 ib_change_view.setImageResource(R.drawable.list);//改变图片 143 MyToast.MyToastShow(MainActivity.this, R.drawable.list,"列表显示",Toast.LENGTH_SHORT); 144 } 145 else 146 ... 147 } 148 }); 149 150 <7> 为ListView和GridView分别设置item点击监听器,在点击view中的item时会触发: 151 gv.setOnItemClickListener(this); 152 lv.setOnItemClickListener(this); 153 复写监听器的onItemClick函数,设置点击后弹出的AlertDialog,并实现 154 public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) { 155 final PackageInfo tempPkgInfo = showPackageInfos.get(position);//由于在类里不能访问局部变量,所以添加final使之能访问 156 157 //创建的构造器 158 AlertDialog.Builder builder = new AlertDialog.Builder(this); 159 builder.setTitle("选项");//显示在它的title栏上 160 //第一项是资源文件的ID,第二项是监听器 161 builder.setItems(R.array.choice,new DialogInterface.OnClickListener() { 162 @Override 163 //which 属性用来判断点击的是列表中的第几项,从0开始计数 164 public void onClick(DialogInterface dialog, int which) { 165 // TODO Auto-generated method stub 166 //实现点击每一项内容的具体操作 167 switch (which) { 168 case 0: //打开 169 String pkgName = tempPkgInfo.packageName; 170 //一般来说默认启动的activity放在0的位置,但直接传会报空指针异常,所以在packageInfos复制时就做了判断 171 //This is only filled in if the flag GET_ACTIVITIES was set. 172 ActivityInfo activityInfo = tempPkgInfo.activities[0]; 173 if(activityInfo==null) { 174 Toast.makeText(MainActivity.this,"没有任何activity", Toast.LENGTH_SHORT); 175 return; 176 } 177 String activityName = activityInfo.name; 178 179 Intent intent = new Intent(); 180 //使用包名+类名的方式将activity启动起来 181 intent.setComponent(new ComponentName(pkgName,activityName)); 182 startActivity(intent); 183 break; 184 case 1: //详细信息 185 showAppDetail(tempPkgInfo); 186 break; 187 case 2: //卸载 188 Uri pkgUri = Uri.parse("package:"+tempPkgInfo.packageName); 189 Intent deleteIntent = new Intent(); 190 deleteIntent.setAction(Intent.ACTION_DELETE); 191 deleteIntent.setData(pkgUri); 192 startActivityForResult(deleteIntent, 0);//解决了一个bug:startActivity(deleteIntent); 193 break; 194 } 195 } 196 }); 197 builder.setNegativeButton("取消", null); //默认将AlertDialog取消掉,是AlertDialog的特定属性 198 builder.create().show();//将菜单显示出来 199 } 200 相关函数 201 private void showAppDetail(PackageInfo pkgInfo) { 202 AlertDialog.Builder builder = new AlertDialog.Builder(this); 203 builder.setTitle("详细信息"); 204 StringBuffer message =new StringBuffer(); 205 message.append("程序名称 "+pkgInfo.applicationInfo.loadLabel(getPackageManager())); 206 message.append("\n包名 "+pkgInfo.packageName); 207 message.append("\n版本号 "+pkgInfo.versionCode); 208 message.append("\n版本名 "+pkgInfo.versionName); 209 210 builder.setMessage(message.toString()); 211 builder.setIcon(pkgInfo.applicationInfo.loadIcon(getPackageManager())); 212 builder.setPositiveButton("确定", null); 213 builder.create().show(); 214 215 } 216 217 <8> 增加动画的效果: 218 1) 控制View的动画 219 alpha(AlphaAnimation) 渐变透明 220 scale(ScaleAnimation) 渐变尺寸伸缩 221 translate(TranslateAnimation) 画面转换、位置移动 222 rotate(RotateAnimation) 画面转移,旋转动画 223 224 2) 控制一个Layout里面子View的动画效果 225 layoutAnimation(LayoutAnimationController) 226 gridAnimation(GridLayoutAnimationController)
1 ## 弹出框AlertDialog创建方法: 2 1、新建builder 3 AlertDialog.Builder builder = new AlertDialog.Builder(this); 4 2、设置title、Dialog中的项目 5 builder.setTitle("详细信息"); 6 //如果有多个项目,就用StringBuffer存放,依次将信息append进去 7 StringBuffer message =new StringBuffer(); 8 message.append("程序名称 "+pkgInfo.applicationInfo.loadLabel(getPackageManager())); 9 message.append("\n包名 "+pkgInfo.packageName); 10 message.append("\n版本号 "+pkgInfo.versionCode); 11 //将消息设置到builder中去 12 builder.setMessage(message.toString()); 13 builder.setIcon(pkgInfo.applicationInfo.loadIcon(getPackageManager())); 14 builder.setPositiveButton("确定", null);//设置下方按钮,第二个参数是监听器,因为会默认关闭,设为null即可 15 builder.create().show();//将Dialog创建并显示出来 16 17 18 ## 为view设置适配器并关联布局文件的方法: 19 1、先在MainActivity中找出view并命名 20 2、为每个view建立一个适配器类,继承某种适配器(BaseAdapter、ArrayAdapter...) 21 复写其方法 22 class GridViewAdapter extends BaseAdapter{ 23 LayoutInflater inflater; //用来寻找layout下xml布局文件并且将其实例化 24 List<PackageInfo> pkgInfos; 25 public GridViewAdapter(Context context,List<PackageInfo> packageInfos){ 26 inflater = LayoutInflater.from(context);//将xml文件转换为视图 27 this.pkgInfos = packageInfos; 28 //复写BaseAdapter的方法 29 public int getCount() { 30 return pkgInfos.size();//返回list的大小 31 } 32 ... 33 public View getView(int position, View convertView, ViewGroup parent) { 34 View view = inflater.inflate(R.layout.gv_item, null);//将布局文件渲染成view 35 //找出view中的控件 36 TextView tv =(TextView)view.findViewById(R.id.gv_item_appname); 37 ImageView iv = (ImageView)view.findViewById(R.id.gv_item_icon); 38 //给view中的控件赋值 39 tv.setText(pkgInfos.get(position).applicationInfo.loadLabel(getPackageManager())); 40 iv.setImageDrawable(pkgInfos.get(position).applicationInfo.loadIcon(getPackageManager())); 41 return view; 42 } 43 } 44 } 45
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。