Android Launcher应用(基础版)

因为最近再弄android相关东西,就想自己弄个桌面程序。

现在只是弄了个大概,以后会完善起来。

功能:展示所有应用程序,单击图标打开,长按图标震动一下,并在图标的左上方出现一个删除图标,用户再单击时就会提示卸载应用程序(没有实现卸载)。

首先我们创建自己的工程Launcher。

然后我们在AndroidManifest.xml

<category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.DEFAULT" />之后我们的AndroidManifest.xml就变成了:

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.wch.launcher" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="7" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name="BenHome" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.VIBRATE" /> </manifest>
也就是当用户按下home键的时候我们就要运行我们的桌面程序,那么就需要用户去选择是启动系统默认还是我们自己的。

接下来我们看我们的MianActivity,增加以下方法来获取当前系统的所有应用程序的信息:

private List<ResolveInfo> loadApps() { Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); return getPackageManager().queryIntentActivities(mainIntent, 0); }
然后我们再来设置我们显示应用程序的UI,我们就采用最基本的GridView来显示。

在此之前我们先需要看下colors.xml这个很简单。

<?xml version="1.0" encoding="utf-8"?> <resources> <color name="bg_color">#e1e7e8</color> <color name="text_color">#000000</color> <color name="button_selected_start_color">#0091e6</color> <color name="button_selected_end_color">#10c0f7</color> <color name="button_pressed_start_color">#0091e6</color> <color name="button_pressed_end_color">#10c0f7</color> <color name="button_defalut_start_color">#bdbebd</color> <color name="button_defalut_end_color">#f7f3f7</color> <color name="button_solid_color">#848284</color> <color name="button_solid_focused_color">#e5e9ef</color> </resources>
主要是设定了一个背景色,以及待会我们要说的gridview click时的样式。

好我们继续看layout文件:

applist.xml

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:background="@color/bg_color" android:layout_height="fill_parent"> <GridView android:layout_width="fill_parent" android:listSelector="@color/bg_color" android:id="@+id/apps_list" android:numColumns="4" android:layout_height="wrap_content"> </GridView> </LinearLayout>
在此我们注意我设置了LinearLayout的background和GridView的listSelector是一样,这是保证不会再click的时候我们的item出现一个系统默认的边框。

applistitem.xml

<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="wrap_content" android:paddingBottom="4dip" android:background="@drawable/bg_alibuymenu_states" android:layout_width="fill_parent"> <ImageView android:layout_height="50dip" android:id="@+id/ItemImage" android:layout_marginTop="20dip" android:layout_width="50dip" android:layout_centerHorizontal="true"> </ImageView> <TextView android:layout_width="wrap_content" android:gravity="center" android:textColor="@color/text_color" android:singleLine="true" android:textSize="16dip" android:layout_below="@+id/ItemImage" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:id="@+id/ItemText"> </TextView> </RelativeLayout>
这个文件大家都明白吧,就是GridView中显示的View的layout内容,采用了相对布局,并设定了background为drawable下自己设定的风格文件。

接下来我们看click的风格样式,很简单。

bg_alibuymenu_states.xml

<?xml version="1.0" encoding="UTF-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:drawable="@drawable/bg_alibuybutton_selected" /> <item android:state_focused="true" android:drawable="@drawable/bg_alibuybutton_selected" /> </selector>

bg_alibuybutton_selected.xml

<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:radius="3dp" /> <stroke android:width="0.5dp" android:color="#62809a" /> <gradient android:startColor="@color/button_selected_start_color" android:endColor="@color/button_selected_end_color" android:type="linear" android:angle="90" android:centerX="0.5" android:centerY="0.5" /> </shape>

bg_alibuybutton_default.xml

<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:radius="3dp" /> <stroke android:width="0.5dp" android:color="#62809a" /> <gradient android:startColor="@color/button_defalut_start_color" android:endColor="@color/button_defalut_end_color" android:type="linear" android:angle="90" android:centerX="0.5" android:centerY="0.5" /> </shape>


大家注意在bg_alibuymenu_states.xml文件中我们没有设定default的样式,因为我不想加任何内容,如果大家需要可以自己修改bg_alibuybutton_default.xml并自己在

bg_alibuymenu_states.xml文件中加上

<item android:drawable="@drawable/bg_alibuybutton_default" />
搞定了这些周边工作我们就来看具体代码的实现:

我做了一个适配器(AppAdapter.java)来填充gridview,

public class AppAdapter extends BaseAdapter { final public static int OPEN = 0; final public static int DELETE = 1; private Map<Integer, Integer> isOpen; public Map<Integer, Integer> getIsOpen() { return isOpen; } private LayoutInflater mInflater; private List<ResolveInfo> mApps; private Context context; public AppAdapter(Context context,List<ResolveInfo> mApps){ this.context = context; this.mApps = mApps; this.mInflater = LayoutInflater.from(this.context); isOpen = new HashMap<Integer, Integer>(); for (int i = 0; i < this.mApps.size(); i++) { isOpen.put(i, OPEN); } } @Override public int getCount() { return mApps.size(); } @Override public Object getItem(int arg0) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { holder = new ViewHolder(); convertView = mInflater.inflate(R.layout.applistitem, null); holder.image = (ImageView) convertView.findViewById(R.id.ItemImage); holder.text = (TextView) convertView.findViewById(R.id.ItemText); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } ResolveInfo info = this.mApps.get(position); holder.text.setText(info.activityInfo.loadLabel(context.getPackageManager())); holder.info = info; holder.position = position; holder.flag = isOpen.get(position); if(holder.flag == OPEN){ holder.image.setImageDrawable(info.activityInfo.loadIcon(context.getPackageManager())); } if(holder.flag == DELETE){ BitmapDrawable bd = (BitmapDrawable)holder.info.activityInfo.loadIcon(context.getPackageManager()); try { holder.image.setImageBitmap(drawImageAtBitmap(bd.getBitmap(), BitmapFactory.decodeStream(context.getResources().getAssets().open("delete.png")))); } catch (IOException e) { Log.e("异常:", e.getMessage()); } } /************************************/ convertView.setOnLongClickListener(new OnLongClickListener(){ @Override public boolean onLongClick(View view) { ViewHolder holder = (ViewHolder)view.getTag(); if(holder.flag == OPEN){ Vibrator mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE); long [] pattern = {100,400}; mVibrator.vibrate(pattern,-1); view.startAnimation(AnimationUtils.loadAnimation(context,R.anim.anim_move)); try { BitmapDrawable bd = (BitmapDrawable)holder.info.activityInfo.loadIcon(context.getPackageManager()); holder.image.setImageBitmap(drawImageAtBitmap(bd.getBitmap(), BitmapFactory.decodeStream(context.getResources().getAssets().open("delete.png")))); } catch (IOException e) { Log.e("异常:", e.getMessage()); } isOpen.put(holder.position, DELETE); holder.flag = DELETE; }else{ Toast.makeText(context, "已经处于删除状态...", Toast.LENGTH_SHORT).show(); } return false; } }); convertView.setOnClickListener(new OnClickListener(){ @Override public void onClick(View view) { ViewHolder vh = (ViewHolder)view.getTag(); if(vh.flag == AppAdapter.OPEN){ Toast.makeText(AppAdapter.this.context, vh.text.getText().toString(), Toast.LENGTH_SHORT).show(); String pkg = vh.info.activityInfo.packageName; String cls = vh.info.activityInfo.name; Intent i = new Intent(); i.setComponent(new ComponentName(pkg, cls)); AppAdapter.this.context.startActivity(i); } if(vh.flag == AppAdapter.DELETE){ new AlertDialog.Builder(AppAdapter.this.context) .setTitle("提示:") .setMessage("确定要卸载该应用程序嘛?") .setCancelable(true) .setPositiveButton("确定", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }) .setNegativeButton("取消", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }).show(); } } }); return convertView; } public static Bitmap drawImageAtBitmap(Bitmap bitmap,Bitmap addBitmap){ int x = bitmap.getWidth(); int y = bitmap.getHeight(); Bitmap newbit = Bitmap.createBitmap(x, y, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(newbit); Paint paint = new Paint(); canvas.drawBitmap(bitmap, 0, 0, paint); canvas.drawBitmap(Bitmap.createBitmap(addBitmap, 0, 0, 12, 12), 0, 0, paint); canvas.save(Canvas.ALL_SAVE_FLAG); canvas.restore(); return newbit; } public final class ViewHolder { public Integer position; public ImageView image; public TextView text; public ResolveInfo info; public int flag; } }

我要说明的是,ViewHolder类的flag属性是用来表示View当前的status的,也就是处于正常情况下还是删除情况下。

代码我就不详解了,看不明白的留言。

BenHome.java

public class BenHome extends Activity {

	private AppAdapter mAdapter;
	private GridView appList;
	private List<ResolveInfo> mInfo;
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.applist);
		this.loadApps();
		appList = (GridView)this.findViewById(R.id.apps_list);
		mAdapter = new AppAdapter(this,mInfo);
		appList.setAdapter(mAdapter);
	}

	private void loadApps() {
		Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
		mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
		mInfo = getPackageManager().queryIntentActivities(mainIntent, 0);
	}
	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
			boolean isHasDelete = false;
			if(mAdapter.getIsOpen().size() > 0){
				for(int i : mAdapter.getIsOpen().keySet()){
					if(mAdapter.getIsOpen().get(i) == AppAdapter.DELETE){
						isHasDelete = true;
						mAdapter.getIsOpen().put(i, AppAdapter.OPEN);
					}
				}
			}
			if(isHasDelete){
				mAdapter.notifyDataSetChanged();
				return true;
			}else{
				this.finish();
			}
		}
		return super.onKeyDown(keyCode, event);
	}
}

动画:

<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromXDelta="-3%p" android:toXDelta="3%p" android:duration="50" android:repeatCount="10"/> </set>

 在按下返回物理键时如若有存在可删除的应用图标,就取消掉。 

所需图标:





截图有瑕疵是因为图标在震动。

谁能告诉我怎么上传附件。我把源码上传上来。

源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值