adwlauncher之workspace操作分析

adwlauncher下载地址:

http://download.csdn.net/detail/comkingfly/4270809


Launcher.java:launcher中主要的activity。一切都是从这个类开始的。看了adwlauncher有几天了,今天写写我自己的体会,主要是关于拖动一个app到workspace,他们触发的一些事件等。

1.安装好adwlauncher之后,首先看到的就是这个界面:


2.然后点击中间的handlerview,就会进入应用程序列表了。首先响应的是DragController.java里的onInterceptTouchEvent(MotionEvent ev)这个方法,用来判断用户的动作是点击,还是移动等。再然后就进入endDrag()里。

DragLayer.java:launcher layout的rootview。DragLayer实际上也是一个抽象的界面,用来处理拖动和对事件进行初步处理然后按情况分发下去,角色是一个controller。它首先用onInterceptTouchEvent(MotionEvent)来拦截所有的touch事件,如果是长按item拖动的话不把事件传下去,直接交由onTouchEvent()处理,这样就可以实现item的移动了,如果不是拖动item的话就把事件传到目标view,交有目标view的事件处理函数做相应处理。如过有要对事件的特殊需求的话可以修改onInterceptTouchEvent(MotionEvent)来实现所需要的功能。

DragController.java:为Drag定义的一个接口。包含一个接口,两个方法和两个静态常量。接口为DragListener(包含onDragStart(),onDragEnd()两个函数),onDragStart()是在刚开始拖动的时候被调用,onDragEnd()是在拖动完成时被调用。在launcher中典型的应用是DeleteZone,在长按拖动item时调用onDragStart()显示,在拖动结束的时候onDragEnd()隐藏。两个函数包括startDrag()和setDragItemInfo().startDrag()用于在拖动是传递要拖动的item的信息以及拖动的方式,setDragItemInfo()用于传递item的参数信息(包括位置以及大小)。两个常量为DRAG_ACTION_MOVE,DRAG_ACTION_COPY来标识拖动的方式,DRAG_ACTION_MOVE为移动,表示在拖动的时候需要删除原来的item,DRAG_ACTION_COPY为复制型的拖动,表示保留被拖动的item。

public boolean onInterceptTouchEvent(MotionEvent ev) {
		 Log.e("DragController", "onInterceptTouchEvent enter");
		final int action = ev.getAction();

		if (action == MotionEvent.ACTION_DOWN) {
			recordScreenSize();
		}

		final int screenX = clamp((int) ev.getRawX(), 0,
				mDisplayMetrics.widthPixels);
		final int screenY = clamp((int) ev.getRawY(), 0,
				mDisplayMetrics.heightPixels);

		switch (action) {
			case MotionEvent.ACTION_MOVE:
				break;

			case MotionEvent.ACTION_DOWN:
				// Remember location of down touch
				mMotionDownX = screenX;
				mMotionDownY = screenY;
				mLastDropTarget = null;
				break;

			case MotionEvent.ACTION_CANCEL:
			case MotionEvent.ACTION_UP:
				if (mDragging) {
					drop(screenX, screenY);
				}
				endDrag();
				break;
		}

		return mDragging;
	}


然后就会触发Launcher.java里的onclick事件。它会判断用户点击的是快捷方式,文件夹还是mHandleView,并进行相应的操作,当用户点击其他位置的时候,不响应任何事件。

	public void onClick(View v) {
		Log.e("Launcher", "onClick enter");
		Object tag = v.getTag();
		int height = v.getHeight();
		int width = v.getWidth();
		Log.e("Launcher", "onClick height=" + height + " width=" + width);
		if (tag instanceof ShortcutInfo) {
			Log.e("Launcher", "onClick shortcutInfo");
			// Open shortcut
			final Intent intent = ((ShortcutInfo) tag).intent;
			int[] pos = new int[2];
			v.getLocationOnScreen(pos);
			intent.setSourceBounds(new Rect(pos[0], pos[1], pos[0]
					+ v.getWidth(), pos[1] + v.getHeight()));
			startActivitySafely(intent, tag);

		} else if (tag instanceof FolderInfo) {
			Log.e("Launcher", "onClick FolderInfo");
			openFolder((FolderInfo) tag);
		} else if (v == mHandleView) {
			if (isAllAppsVisible()) {
				Log.e("Launcher", "onClick closeAllApps");
				closeAllApps(true);
			} else {
				Log.e("Launcher", "onClick showAllApps");
				showAllApps(true);
			}
		}
	}

3.点击mHandleView后进入程序列表,这里触发了Launcher.java里的showAllApps(true)这个方法。


4.任意的拖动一个app图标到workspace里


还是触发DragController.java里的onInterceptTouchEvent(MotionEvent ev),再然后触发onTouchEvent(MotionEvent ev),然后就是findDropTarget(int x, int y, int[] dropCoordinates),因为滑动图标是会覆盖在其他的图标上面,所以又会触发FolderIcon.java里的onDragOver(DragSource source, int x, int y, int xOffset,int yOffset, DragView dragView, Object dragInfo)

然后就是一直调用这些方法,直到把app拖动到桌面的某个位置上。

ItemInfo.java:对item的抽象,所有类型item的父类,item包含的属性有id(标识item的id),cellX(在横向位置上的位置,从0开始),cellY(在纵向位置上的位置,从0开始) ,spanX(在横向位置上所占的单位格),spanY(在纵向位置上所占的单位格),screen(在workspace的第几屏,从0开始),itemType(item的类型,有widget,search,application等),container(item所在的)。



5.当app放到桌面时,就会触发workspace.java里的onDropExternal()了。然后就是保存到数据库里,都是在LauncherModel.java这个类里增删改查这些数据,里面有许多封装的对数据库的操作。包含几个线程,其中最主要的是ApplicationsLoader和DesktopItemsLoader。ApplicationsLoader在加载所有应用程序时使用,DesktopItemsLoader在加载workspace的时候使用。其他的函数就是对数据库的封装,比如在删除,替换,添加程序的时候做更新数据库和UI的工作。

LauncherProvider.java:launcher的数据库,里面存储了桌面的item的信息。在创建数据库的时候会loadFavorites(db)方法,loadFavorites()会解析xml目录下的default_workspace.xml文件,把其中的内容读出来写到数据库中,这样就做到了桌面的预制。

6.当在workspace点击文件夹时,就会触发Launcher.java里的onClick()事件,然后再是openFolder(FolderInfo folderInfo),再然后就是doOpenFolder(FolderInfo folderInfo)这个方法了,这个里面就会弹出打开的文件夹,相关布局文件在user_folder.xml这个文件里。workspace.java里就会执行addInScreen(View child, int screen, int x, int y, int spanX, int spanY),也就是弹出的这个布局的整体的显示位置。在然后就是进入CellLayout.java里的onMeasure()里进行一些处理。

UserFolder.java: 用户创建的文件夹。可以将item拖进文件夹,单击时打开文件夹,长按文件夹上面标题处可以重命名文件夹。

LiveFolder.java:系统自带的文件夹。从系统中创建出的如联系人的文件夹等。 

DeleteZone:删除框。在平时是出于隐藏状态,在将item长按拖动的时候会显示出来,如果将item拖动到删除框位置时会删除item。DeleteZone实现了DropTarget和DragListener两个接口。

CellLayout.java:组成workspace的view,继承自viewgroup,既是一个dragSource,又是一个dropTarget,可以将它里面的item拖出去,也可以容纳拖动过来的item。在workspace_screen里面定了一些它的view参数。

8.Launcher的界面的rootviewDragLayer,它是一个FrameLayout,在它上面workspace(应该说是celllayout)占了绝大部分的空间,celllayout的参数文件是workspace_screen.xmlworkspace既是一个DropTarget又是一个DragSource,可以从AllAppGridView中拖出应用程序放在它上面,也可以把它里面的item拖走删除或者拖到bottomabr里面去。8.

(对于想修改launcher的同学,可以自定义DragLay.java,比如改为AbsoluteLayout等,再修改launcher.xml布局文件,就可以实现各种样式的launcher几面。)

由于launcher的事件比较多比较复杂,所以在事件处理的时候一般采用rootview先用onInterceptTouchEvent(MotionEvent)拦截所有的touch事件,经过判断后分发给childview。

判断的规则如下:

       a.down事件首先会传递到onInterceptTouchEvent()方法

       b.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标view的onTouchEvent()处理。

       c.如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。

       d.如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理。

       e.如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。

9.

在../res/xml下的default_workspace.xml文件中加入默认要放置的普通的应用程序。加入的格式为:

<favorite

launcher:packageName="... "    //应用的packageName  

launcher:className="... "      //应用启动时的第一个activity 

launcher:screen="..."         //放置在第几屏(放在workspace的时候需要,从0开始,0为第一屏,1为第二屏,以此类推...)

launcher:x="..."               //放置x方向的位置(在列中的位置)

launcher:y="..." />           //放置y方向的位置(在行中的位置)

packageName和className可以通过点击程序,然后在打印出的log中找到comp={...},例如如下信息:

comp={com.estrongs.android.taskmanager/com.estrongs.android.taskmanager.TaskManager}。其中com.estrongs.android.taskmanager为packageName, com.estrongs.android.taskmanager.TaskManager为className。

workspace的布局如下:

(0,0)

(1,0)

(2,0)

(3,0)

(4,0)

(0,1)

(1,1)

(2,1)

(3,1)

(4,1)

(0,2)

(1,2)

(2,2)

(3,2)

(4,2)

  b.添加widget:

         在../package/apps/VLauncher/res/xml下的default_workspace.xml文件中加入默认要放置的普通的应用程序。加入的格式为:

<widget

launcher:packageName="..."       //widget的packageName

launcher:className=" ..."       //实现 widget的 receiver 类的名称.

    launcher:container="..."        //放置的位置(只能为desktop)

        launcher:screen="..."        //放置在第几屏上

        launcher:x="..."              //放置的x位置

        launcher:y="..."              //放置的y位置

        launcher:spanx="..."         //在x方向上所占格数

        launcher:spany="..."/>       //在y方向上所占格数

例如,要在第3屏的第一行第二列放置开始放置一个x方向上占两个单位格,y方向上占两个单位格的时钟,可以加入以下代码:

<appwidget

launcher:packageName="com.android.alarmclock"       launcher:className="com.android.alarmclock.AnalogAppWidgetProvider"

        launcher:container="desktop"

        launcher:screen="2"

        launcher:x="1"

        launcher:y="0"

        launcher:spanx="2"

        launcher:spany="2"/> 

c.

        launcher:cellWidth="95dip"   cell(即item)的宽

        launcher:cellHeight="93dip"  cell(即item)的宽

        launcher:longAxisStartPadding="25dip"

较长(屏幕的宽和高中较大的那一方向,根据横竖屏方向有所不同)方向上距离起点的像素数

        launcher:longAxisEndPadding="55dip"

较长(屏幕的宽和高中较大的那一方向,根据横竖屏方向有所不同)方向上距离终点的像素数

        launcher:shortAxisStartPadding="20dip"

较短(屏幕的宽和高中较大的那一方向,根据横竖屏方向有所不同)方向上距离起点的像素数

        launcher:shortAxisEndPadding="120dip"

较短(屏幕的宽和高中较大的那一方向,根据横竖屏方向有所不同)方向上距离起点的像素数

        launcher:shortAxisCells="3"

较短的方向上可以容纳的cell的数量

        launcher:longAxisCells="5"

较长的方向上可以容纳的cell的数量

shortAxisCells和longAxisCells决定一个workspace(即CellLayout)上可以容纳的item的个数为shortAxisCells*longAxisCells.


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值