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>


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

所需图标:





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

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

源码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值