android4.0 Launcher仿三星平板workspace页面编辑(即页面增减)

来源:互联网 发布:淘宝网的整体构架 编辑:程序博客网 时间:2024/05/02 10:02

本文主要讲android4.0 Launcher添加页面编辑功能,样式同三星的平板。

一、已实现功能:

1、页面增减(最多8个页面、拖动删除、最后一个添加页面、有内容的页面不可删除)

2、自由拖动交换位置

3、页面位置布局(完全仿三星位置布局)、目前是固定大小的。。。为什么要仿它,纠结

布局图:



二、开始思路

1、自定义一个view,实现添加、自由拖动、删除等功能

2、开始页面编辑时,将已有的页面生成缩略图传入到自定义的view中显示

3、编辑完成后,将新的页面顺序传出来,对Workspace的CellLayout进行重新排序(调整顺序,生成新加的页面,删除删除了的页面)

4、更新数据库中CellLayout上面item的screen属性

5、将现有的页面数量定入到文件中或者数据库

6、启动launcher时,workspace中CellLayout的数量初始化通过读取已保存的页面数据

三、相关代码

1、自定义的页面编辑View-------HomeEditView.java

package com.launcher.edit;import java.util.ArrayList;import java.util.Arrays;import java.util.List;import android.content.Context;import android.content.res.Resources;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.ColorFilter;import android.graphics.LightingColorFilter;import android.graphics.Paint;import android.graphics.Point;import android.graphics.Rect;import android.graphics.Typeface;import android.graphics.Paint.Style;import android.util.AttributeSet;import android.util.Log;import android.util.SparseArray;import android.util.TypedValue;import android.view.Gravity;import android.view.MotionEvent;import android.view.View;import android.view.View.OnClickListener;import android.view.View.OnLongClickListener;import android.view.View.OnTouchListener;import android.view.animation.AccelerateDecelerateInterpolator;import android.view.animation.Animation;import android.view.animation.AnimationSet;import android.view.animation.RotateAnimation;import android.view.animation.ScaleAnimation;import android.view.animation.TranslateAnimation;import android.view.ViewGroup;import android.widget.TextView;import com.android.launcher.R;/** * 页面编辑 * 当前页面是否可删除用view的id判断,当id > 0时不可删除,否则是可以删除的,所以在传入view时,要根据是否可删除设置好id * 用tag标记页面原来的页面索引 * @author wusj *  */public class HomeEditView extends ViewGroup implements OnTouchListener,OnLongClickListener {private static final String TAG = "HomeEditView";private Context mContext;private List<View> mChilds;// view从一点移到另一点时的平移动画时长private static final int ANIMATION_DURATION = 250;// 小于等于4个时的宽度和高度private static final int SMALL_WIDTH = 300;private static final int SMALL_HEIGHT = 300;// 大于4个页面时,单个页面显示的宽度和高度private static final int BIG_WIDTH = 250;private static final int BIG_HEIGHT = 250;// 水平两页面之间的间隙private static final int PAGE_GAP_WIDTH = 5;// 竖直两页面之间的间隙private static final int PAGE_GAP_HEIGHT = 5;// 删除区域的高度private static final int DELETE_ZONE_HEIGHT = 40;int dragged = -1;// 当前是否在移动viewprivate boolean movingView = false;private int dragLeft;private int dragTop;private TextView add;public interface OnClickPageListener {public void onClickPage(int index, List<PageInfo> pages);}private OnClickPageListener clickPage;public void setOnClickPageListener(OnClickPageListener listener) {this.clickPage = listener;}private OnClickListener onClickListener = new OnClickListener() {@Overridepublic void onClick(View v) {Log.d(TAG, "onClick");if (v == add) {View view = createView(getChildCount() - 2);addView(view, getChildCount() - 2);// view.setOnClickListener(this);if (getChildCount() == 10) {Log.d(TAG, "已经达到最大页面数, 删除添加按钮");removeView(add);}requestLayout();} else {if (clickPage != null) {List<PageInfo> pages = new ArrayList<PageInfo>();for (int i = 0; i < getChildCount() - 1; i++) {View child = getChildAt(i);if (child == add) {continue;}PageInfo info = new PageInfo();info.originPage = (Integer) child.getTag();//Log.d(TAG, "tag : " + info.originPage);info.currentPage = i;pages.add(info);}clickPage.onClickPage(0, pages);}}}};// 前面是view后面是view所在的位置private SparseArray<Integer> newPositions = new SparseArray<Integer>();private int initX;private int initY;private int lastTouchX;private int lastTouchY;private int lastTarget = -1;private Point startPoint;private DeleteDropZoneView deleteZone;public HomeEditView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public HomeEditView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);this.mContext = context;setOnTouchListener(this);setOnLongClickListener(this);}public void addViews(List<View> views) {removeAllViews();for (int i = 0; i < views.size(); i++) {View view = views.get(i);addView(view);view.setTag(i);newPositions.put(i, i);}if (views.size() < 8) {addView(createAddView());}// 将删除区域放到最后面createDeleteZone();}private void printTag() {for (int i = 0; i < getChildCount(); i++) {View child = getChildAt(i);// Log.d(TAG, "Tag : " + child.getTag());}// Log.d(TAG, "-----------------------------");}@Overridepublic boolean onTouch(View v, MotionEvent event) {int action = event.getAction();switch (action & MotionEvent.ACTION_MASK) {case MotionEvent.ACTION_DOWN:initX = (int) event.getX();initY = (int) event.getY();lastTouchX = (int) event.getX();lastTouchY = (int) event.getY();break;case MotionEvent.ACTION_MOVE:eventMove(event);break;case MotionEvent.ACTION_UP:touchUp(event);break;default:break;}if (aViewIsDragged()) {return true;}return false;}private void touchUp(MotionEvent event) {if (!aViewIsDragged()) {if (onClickListener != null) {View clickedView = getChildAt(getTargetAtCoor((int) event.getX(), (int) event.getY()));Log.d(TAG, "clickedView : " + clickedView);                if(clickedView != null)                    onClickListener.onClick(clickedView);}} else {hideDeleteView();manageChildrenReordering();movingView = false;dragged = -1;lastTarget = -1;cancelAnimations();}}private void cancelAnimations() {for (int i = 0; i < getChildCount(); i++) {if (i != dragged) {View child = getChildAt(i);child.clearAnimation();}}}private void manageChildrenReordering() {boolean draggedDeleted = touchUpInDeleteZoneDrop(lastTouchX, lastTouchY);if (draggedDeleted) {View view = getChildAt(dragged);int id = view.getId();Log.d(TAG, "id : " + id);if (id > 0) {draggedDeleted = false;}}if (draggedDeleted) {animateDeleteDragged();reorderChildrenWhenDraggedIsDeleted();} else {reorderChildren();}}// 当有页面被删除时,重新排列viewprivate void reorderChildrenWhenDraggedIsDeleted() {Integer newDraggedPosition = newPositions.get(dragged,dragged);List<View> children = cleanUnorderedChildren();addReorderedChildrenToParent(children);//tellAdapterDraggedIsDeleted(newDraggedPosition);removeViewAt(newDraggedPosition);if (add != null && add.getParent() != this) {addView(createAddView(), getChildCount() - 1);}requestLayout();}// 删除时的缩小动画private void animateDeleteDragged() {ScaleAnimation scale = new ScaleAnimation(1.4f, 0f, 1.4f, 0f);//, biggestChildWidth / 2 , biggestChildHeight / 2);scale.setDuration(200);scale.setFillAfter(true);scale.setFillEnabled(true);getChildAt(dragged).clearAnimation();getChildAt(dragged).startAnimation(scale);}private void reorderChildren() {List<View> children = cleanUnorderedChildren();addReorderedChildrenToParent(children);requestLayout();}private void removeItemChildren(List<View> children) {for (View child : children) {removeView(child);}}private List<View> cleanUnorderedChildren() {List<View> children = saveChildren();removeItemChildren(children);return children;}private void addReorderedChildrenToParent(List<View> children) {List<View> reorderedViews = reeorderView(children);newPositions.clear();for (View view : reorderedViews) {if (view != null)addView(view);}}// 重新排列viewprivate List<View> reeorderView(List<View> children) {View[] views = new View[children.size()];for (int i = 0; i < children.size(); i++) {int position = newPositions.get(i, -1);if (position != -1) {views[position] = children.get(i);} else {views[i] = children.get(i);}}return new ArrayList<View>(Arrays.asList(views));}// 将view保存返回private List<View> saveChildren() {List<View> children = new ArrayList<View>();for (int i = 0; i < getChildCount(); i++) {View child = getChildAt(i);child.clearAnimation();children.add(child);}return children;}private void eventMove(MotionEvent event) {if (movingView && aViewIsDragged()) {lastTouchX = (int) event.getX();lastTouchY = (int) event.getY();moveDraggedView(lastTouchX, lastTouchY);manageSwapPosition(lastTouchX, lastTouchY);manageDeleteZoneHover(lastTouchX, lastTouchY);}}// 移动时的位置交换管理private void manageSwapPosition(int x, int y) {int target = getTargetAtCoor(x, y);// Log.d(TAG, "target : " + target);if (target != -1 && target != lastTarget) {animateGap(target);lastTarget = target;}}// 通过后面的位置(value),得到前面的view(key)private int currentViewAtPosition(int targetLocation) {int viewAtPosition = targetLocation;for (int i = 0; i < newPositions.size(); i++) {int value = newPositions.valueAt(i);if (value == targetLocation) {viewAtPosition = newPositions.keyAt(i);break;}}return viewAtPosition;}private void animateGap(int target) {int viewAtPosition = currentViewAtPosition(target);if (getChildAt(viewAtPosition) == add) {return;}// 源始位置View origin = getChildAt(viewAtPosition);int originLeft = origin.getLeft();int originTop = origin.getTop();if (viewAtPosition == dragged) {originLeft = dragLeft;originTop = dragTop;}// 当前位置View curr = getChildAt(target);int currLeft = curr.getLeft();int currTop = curr.getTop();if (target == dragged) {currLeft = dragLeft;currTop = dragTop;}// 将要到达位置View tar = getChildAt(newPositions.get(dragged, dragged));int tarLeft = tar.getLeft();int tarTop = tar.getTop();if (newPositions.get(dragged, dragged) == dragged) {tarLeft = dragLeft;tarTop = dragTop;}Point oldOffset = new Point();oldOffset.x = currLeft - originLeft;oldOffset.y = currTop - originTop;Point newOffset = new Point();newOffset.x = tarLeft - originLeft;newOffset.y = tarTop - originTop;animateMoveToNewPosition(getChildAt(viewAtPosition), oldOffset,newOffset);saveNewPosition(target, viewAtPosition);}private void saveNewPosition(int target, int viewInTarget) {newPositions.put(viewInTarget, newPositions.get(dragged, dragged));newPositions.put(dragged, target);}// 取得指定点上的view的索引private int getTargetAtCoor(int x, int y) {int ret = -1;// 减1说明:最后的deleteZonefor (int i = 0; i < getChildCount() - 1; i++) {View child = getChildAt(i);if (child == getChildAt(dragged)) {// if (dragged != i)int count = getChildCount();if (count < 5) {if ((x > dragLeft && x < dragLeft + SMALL_WIDTH)&& (y > dragTop && y < dragTop + SMALL_HEIGHT)) {return i;}} else {if ((x > dragLeft && x < dragLeft + BIG_WIDTH)&& (y > dragTop && y < dragTop + BIG_HEIGHT)) {return i;}}continue;}if (isPointInsideView(x, y, child)) {return i;}}return ret;}// 移动被拖曳的viewprivate void moveDraggedView(int x, int y) {View childAt = getChildAt(dragged);int width = childAt.getMeasuredWidth();int height = childAt.getMeasuredHeight();int l = x - (1 * width / 2);int t = y - (1 * height / 2);childAt.layout(l, t, l + width, t + height);}// 调整view的大小private void updateSize() {int count = getChildCount() - 1;if (count < 5) {for (int i = 0; i < count; i++) {View view = getChildAt(i);float wid = view.getWidth();float hei = view.getHeight();view.setScaleX(SMALL_WIDTH / wid);view.setScaleY(SMALL_HEIGHT / hei);}} else {for (int i = 0; i < count; i++) {View view = getChildAt(i);float wid = view.getWidth();float hei = view.getHeight();view.setScaleX(BIG_WIDTH / wid);view.setScaleY(BIG_HEIGHT / hei);}}}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {int count = getChildCount() - 1;// updateSize();Log.d(TAG, "count == " + count);if (count < 3) {int left = getWidth() / 2 - (SMALL_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;for (int i = 0; i < count; i++) {View child = getChildAt(i);if (child.getVisibility() == View.GONE) {continue;}child.layout(left, DELETE_ZONE_HEIGHT, left + SMALL_WIDTH,SMALL_HEIGHT + DELETE_ZONE_HEIGHT);left += SMALL_WIDTH + PAGE_GAP_WIDTH;}} else if (count == 3) {int left = getWidth() / 2 - (SMALL_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;for (int i = 0; i < count; i++) {View child = getChildAt(i);if (child.getVisibility() == View.GONE) {continue;}if (i == 2) {child.layout(getWidth() / 2 - SMALL_WIDTH / 2, SMALL_HEIGHT+ PAGE_GAP_HEIGHT + DELETE_ZONE_HEIGHT, getWidth()/ 2 - SMALL_WIDTH / 2 + SMALL_WIDTH, SMALL_HEIGHT* 2 + PAGE_GAP_HEIGHT + DELETE_ZONE_HEIGHT);} else {child.layout(left, DELETE_ZONE_HEIGHT, left + SMALL_WIDTH,SMALL_HEIGHT + DELETE_ZONE_HEIGHT);left += SMALL_WIDTH + PAGE_GAP_WIDTH;}}} else if (count == 4) {int left = getWidth() / 2 - (SMALL_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;int left2 = getWidth() / 2 - (SMALL_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;for (int i = 0; i < count; i++) {View child = getChildAt(i);if (child.getVisibility() == View.GONE) {continue;}if (i >= 2) {child.layout(left2, SMALL_HEIGHT + PAGE_GAP_HEIGHT+ DELETE_ZONE_HEIGHT, left2 + SMALL_WIDTH,SMALL_HEIGHT * 2 + PAGE_GAP_HEIGHT+ DELETE_ZONE_HEIGHT);left2 += SMALL_WIDTH + PAGE_GAP_WIDTH;} else {child.layout(left, DELETE_ZONE_HEIGHT, left + SMALL_WIDTH,SMALL_HEIGHT + DELETE_ZONE_HEIGHT);left += SMALL_WIDTH + PAGE_GAP_WIDTH;}}} else if (count == 5) {int left1 = getWidth() / 2 - (BIG_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;int left2 = getWidth() / 2 - (BIG_WIDTH / 2);int left3 = getWidth() / 2 - (BIG_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;for (int i = 0; i < count; i++) {View child = getChildAt(i);if (child.getVisibility() == View.GONE) {continue;}if (i < 2) {child.layout(left1, DELETE_ZONE_HEIGHT, left1 + BIG_WIDTH,BIG_HEIGHT + DELETE_ZONE_HEIGHT);left1 += BIG_WIDTH + PAGE_GAP_WIDTH;} else if (i == 2) {child.layout(left2, BIG_HEIGHT + PAGE_GAP_HEIGHT+ DELETE_ZONE_HEIGHT, left2 + BIG_WIDTH, BIG_HEIGHT* 2 + PAGE_GAP_HEIGHT + DELETE_ZONE_HEIGHT);} else {child.layout(left3, BIG_HEIGHT * 2 + PAGE_GAP_HEIGHT * 2+ DELETE_ZONE_HEIGHT, left3 + BIG_WIDTH, BIG_HEIGHT* 2 + PAGE_GAP_HEIGHT * 2 + BIG_HEIGHT+ DELETE_ZONE_HEIGHT);left3 += BIG_WIDTH + PAGE_GAP_WIDTH;}}} else if (count == 6) {int left1 = getWidth() / 2 - (BIG_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;int left2 = left1;int left3 = getWidth() / 2 - (BIG_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;for (int i = 0; i < count; i++) {View child = getChildAt(i);if (child.getVisibility() == View.GONE) {continue;}if (i < 2) {child.layout(left1, DELETE_ZONE_HEIGHT, left1 + BIG_WIDTH,BIG_HEIGHT + DELETE_ZONE_HEIGHT);left1 += BIG_WIDTH + PAGE_GAP_WIDTH;} else if (i >= 2 && i < 4) {child.layout(left2, BIG_HEIGHT + PAGE_GAP_HEIGHT+ DELETE_ZONE_HEIGHT, left2 + BIG_WIDTH, BIG_HEIGHT* 2 + PAGE_GAP_HEIGHT + DELETE_ZONE_HEIGHT);left2 += BIG_WIDTH + PAGE_GAP_WIDTH;} else {child.layout(left3, BIG_HEIGHT * 2 + PAGE_GAP_HEIGHT * 2+ DELETE_ZONE_HEIGHT, left3 + BIG_WIDTH, BIG_HEIGHT* 2 + PAGE_GAP_HEIGHT * 2 + BIG_HEIGHT+ DELETE_ZONE_HEIGHT);left3 += BIG_WIDTH + PAGE_GAP_WIDTH;}}} else if (count == 7) {int left1 = getWidth() / 2 - (BIG_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;int left2 = getWidth() / 2 - (BIG_WIDTH * 3 + 2 * PAGE_GAP_WIDTH)/ 2;int left3 = getWidth() / 2 - (BIG_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;for (int i = 0; i < count; i++) {View child = getChildAt(i);if (child.getVisibility() == View.GONE) {continue;}if (i < 2) {child.layout(left1, DELETE_ZONE_HEIGHT, left1 + BIG_WIDTH,BIG_HEIGHT + DELETE_ZONE_HEIGHT);left1 += BIG_WIDTH + PAGE_GAP_WIDTH;} else if (i >= 2 && i < 5) {child.layout(left2, BIG_HEIGHT + PAGE_GAP_HEIGHT+ DELETE_ZONE_HEIGHT, left2 + BIG_WIDTH, BIG_HEIGHT* 2 + PAGE_GAP_HEIGHT + DELETE_ZONE_HEIGHT);left2 += BIG_WIDTH + PAGE_GAP_WIDTH;} else {child.layout(left3, BIG_HEIGHT * 2 + PAGE_GAP_HEIGHT * 2+ DELETE_ZONE_HEIGHT, left3 + BIG_WIDTH, BIG_HEIGHT* 2 + PAGE_GAP_HEIGHT * 2 + BIG_HEIGHT+ DELETE_ZONE_HEIGHT);left3 += BIG_WIDTH + PAGE_GAP_WIDTH;}}} else if (count == 8) {int left1 = getWidth() / 2 - (BIG_WIDTH * 3 + 2 * PAGE_GAP_WIDTH)/ 2;int left2 = getWidth() / 2 - (BIG_WIDTH * 2 + PAGE_GAP_WIDTH) / 2;int left3 = left1;for (int i = 0; i < count; i++) {View child = getChildAt(i);if (child.getVisibility() == View.GONE) {continue;}if (i < 3) {child.layout(left1, DELETE_ZONE_HEIGHT, left1 + BIG_WIDTH,BIG_HEIGHT + DELETE_ZONE_HEIGHT);left1 += BIG_WIDTH + PAGE_GAP_WIDTH;} else if (i >= 3 && i < 5) {child.layout(left2, BIG_HEIGHT + PAGE_GAP_HEIGHT+ DELETE_ZONE_HEIGHT, left2 + BIG_WIDTH, BIG_HEIGHT* 2 + PAGE_GAP_HEIGHT + DELETE_ZONE_HEIGHT);left2 += BIG_WIDTH + PAGE_GAP_WIDTH;} else {child.layout(left3, BIG_HEIGHT * 2 + PAGE_GAP_HEIGHT * 2+ DELETE_ZONE_HEIGHT, left3 + BIG_WIDTH, BIG_HEIGHT* 2 + PAGE_GAP_HEIGHT * 2 + BIG_HEIGHT+ DELETE_ZONE_HEIGHT);left3 += BIG_WIDTH + PAGE_GAP_WIDTH;}}}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {Log.d(TAG, "onMeasure");super.onMeasure(widthMeasureSpec, heightMeasureSpec);int count = getChildCount();//updateSize();if (count < 5) {for (int i = 0; i < count; i++) {View child = getChildAt(i);child.measure(MeasureSpec.makeMeasureSpec(SMALL_WIDTH,MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(SMALL_HEIGHT, MeasureSpec.EXACTLY));}} else {for (int i = 0; i < count; i++) {View child = getChildAt(i);child.measure(MeasureSpec.makeMeasureSpec(BIG_WIDTH,MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(BIG_HEIGHT, MeasureSpec.EXACTLY));}}measureChild(deleteZone, MeasureSpec.makeMeasureSpec(getWidth(),MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(DELETE_ZONE_HEIGHT, MeasureSpec.EXACTLY));}private float getPixelFromDip(int size) {Resources r = getResources();float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size,r.getDisplayMetrics());return px;}@Overridepublic boolean onLongClick(View v) {if ((dragged = positionForView()) != -1) {if (getChildAt(dragged) == add) {// 长按的是添加按钮则不可移动return true;}startPoint = new Point();// getLeft()和getTop()取相对父控件的距离dragLeft = (int) getChildAt(dragged).getLeft();dragTop = (int) getChildAt(dragged).getTop();movingView = true;animateMoveAllItems();animateDragged();popDeleteView();return true;}return false;}// 长按时,判断当前按下的是不是一个页面private int positionForView() {for (int i = 0; i < getChildCount(); i++) {View child = getChildAt(i);if (isPointInsideView(initX, initY, child)) {return i;}}return -1;}// 判断按下的点是不是在view上private boolean isPointInsideView(float x, float y, View view) {int viewX = view.getLeft();int viewY = view.getTop();if (pointIsInsideViewBounds(x, y, view, viewX, viewY)) {return true;} else {return false;}}private boolean pointIsInsideViewBounds(float x, float y, View view,int viewX, int viewY) {return (x > viewX && x < (viewX + view.getWidth()))&& (y > viewY && y < (viewY + view.getHeight()));}// 启动其它页面的跳动动画private void animateMoveAllItems() {Animation rotateAnimation = createFastRotateAnimation();for (int i = 0; i < getChildCount() - 1; i++) {View child = getChildAt(i);child.startAnimation(rotateAnimation);}}// 拖拽时其它页面的跳动动画private Animation createFastRotateAnimation() {Animation rotate = new RotateAnimation(-2.0f, 2.0f,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,0.5f);rotate.setRepeatMode(Animation.REVERSE);rotate.setRepeatCount(Animation.INFINITE);rotate.setDuration(60);rotate.setInterpolator(new AccelerateDecelerateInterpolator());return rotate;}// 给被拖曳的item加放大动画private void animateDragged() {ScaleAnimation scale = new ScaleAnimation(1f, 1.4f, 1f, 1.4f);// ,// biggestChildWidth// / 2 ,// biggestChildHeight// / 2);scale.setDuration(200);scale.setFillAfter(true);scale.setFillEnabled(true);if (aViewIsDragged()) {getChildAt(dragged).clearAnimation();getChildAt(dragged).startAnimation(scale);}}// old动画起始点相对view的距离,new动画终点相对view的距离private TranslateAnimation createTranslateAnimation(Point oldOffset,Point newOffset) {TranslateAnimation translate = new TranslateAnimation(Animation.ABSOLUTE, oldOffset.x, Animation.ABSOLUTE,newOffset.x, Animation.ABSOLUTE, oldOffset.y,Animation.ABSOLUTE, newOffset.y);translate.setDuration(ANIMATION_DURATION);translate.setFillEnabled(true);translate.setFillAfter(true);translate.setInterpolator(new AccelerateDecelerateInterpolator());return translate;}private void animateMoveToNewPosition(View targetView, Point oldOffset,Point newOffset) {AnimationSet set = new AnimationSet(true);Animation rotate = createFastRotateAnimation();Animation translate = createTranslateAnimation(oldOffset, newOffset);set.addAnimation(rotate);set.addAnimation(translate);targetView.clearAnimation();targetView.startAnimation(set);}private boolean aViewIsDragged() {return dragged != -1;}// 点击添加时、创建一个新viewprivate View createView(int count) {TextView tv = new TextView(mContext);tv.setWidth(50);tv.setHeight(50);tv.setBackgroundColor(Color.CYAN);tv.setTag(-1);tv.setId(0);tv.setText("" + count);return tv;}// 显示删除区域private void popDeleteView() {deleteZone.setVisibility(View.VISIBLE);deleteZone.layout(0, 0, deleteZone.getMeasuredWidth(),deleteZone.getMeasuredHeight());}private void createDeleteZone() {deleteZone = new DeleteDropZoneView(getContext());addView(deleteZone);deleteZone.setVisibility(View.GONE);}// 创建显示在最后的添加viewprivate TextView createAddView() {if (add != null) {return add;}add = new TextView(getContext());add.setBackgroundColor(Color.CYAN);add.setGravity(Gravity.CENTER);add.setText("+");return add;}private void hideDeleteView() {deleteZone.setVisibility(View.GONE);}// 拖动放开时,判断是否在删除区域中private boolean touchUpInDeleteZoneDrop(int x, int y) {Rect zone = new Rect();deleteZone.getHitRect(zone);if (zone.intersect(x, y, x + 1, y + 1)) {deleteZone.smother();return true;}return false;}// 移动到删除区域时,高亮显示private void manageDeleteZoneHover(int x, int y) {Rect zone = new Rect();deleteZone.getHitRect(zone);if (zone.intersect(x, y, x + 1, y + 1)) {deleteZone.highlight();} else {deleteZone.smother();}}}class DeleteDropZoneView extends View {private Paint textPaintStraight;private Paint textPaintRed;private Paint bitmapPaint;private Paint bitmapPaintRed;private boolean straight = true;private Bitmap trash;private Rect bounds;public DeleteDropZoneView(Context context) {super(context);bounds = new Rect();textPaintStraight = createTextPaint();textPaintStraight.setColor(Color.WHITE);textPaintRed = createTextPaint();textPaintRed.setColor(Color.RED);bitmapPaint = createBaseBitmapPaint();bitmapPaintRed = createBaseBitmapPaint();ColorFilter filter = new LightingColorFilter(Color.RED, 1);bitmapPaintRed.setColorFilter(filter);setBackgroundColor(Color.BLACK);getBackground().setAlpha(200);}private Paint createTextPaint() {Paint textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);textPaint.setStyle(Style.FILL);textPaint.setTextAlign(Paint.Align.CENTER);textPaint.setTypeface(Typeface.DEFAULT_BOLD);return textPaint;}private Paint createBaseBitmapPaint() {Paint bitmapPaint = new Paint();bitmapPaint.setAntiAlias(true);bitmapPaint.setFilterBitmap(true);bitmapPaint.setDither(true);return bitmapPaint;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);int measuredHeight = getMeasuredHeight();int measuredWidth = getMeasuredWidth();String removeString = "Remove";// getResources().getString(R.string.removeItem);initTrashIcon();textPaintStraight.getTextBounds(removeString, 0, 6, bounds);int proportion = 3 * measuredHeight / 4;if (straight) {textPaintStraight.setTextSize(proportion);canvas.drawText(removeString,(measuredWidth / 2) + (trash.getWidth() / 2) + 5,measuredHeight - ((measuredHeight - bounds.height()) / 2),textPaintStraight);canvas.drawBitmap(trash, (measuredWidth / 2) - (bounds.width() / 2)- (trash.getWidth() / 2) - 10, 0, bitmapPaint);} else {textPaintRed.setTextSize(proportion);canvas.drawText(removeString,(measuredWidth / 2) + (trash.getWidth() / 2) + 5,measuredHeight - ((measuredHeight - bounds.height()) / 2),textPaintRed);canvas.drawBitmap(trash, (measuredWidth / 2) - (bounds.width() / 2)- (trash.getWidth() / 2) - 10, 0, bitmapPaintRed);}}private void initTrashIcon() {if (trash == null) {trash = getImage(R.drawable.content_discard, getMeasuredHeight(),getMeasuredHeight());}}public void highlight() {straight = false;invalidate();}public void smother() {straight = true;invalidate();}private Bitmap getImage(int id, int width, int height) {Bitmap bmp = BitmapFactory.decodeResource(getResources(), id);Bitmap img = Bitmap.createScaledBitmap(bmp, width, height, true);bmp.recycle();invalidate();return img;}}

2、launcher.xml中添加自定义的view,注意要Gone

<com.launcher.edit.HomeEditView    android:id="@+id/gridview"    android:visibility="gone"    android:layout_width="fill_parent"    android:layout_height="fill_parent" />

3、在Launcher.java中添加开始编辑方法(触发条件自已加吧), mDragGrid我定义成了成员字段

    private void startEdit() {    Log.d(TAG, "*******onLongClick AllAppsButton**********");mDragGrid = (HomeEditView) findViewById(R.id.gridview);mDragGrid.setOnClickPageListener(listener);List<View> views = new ArrayList<View>();for (int i = 0; i < mWorkspace.getChildCount(); i++) {// 将当前已有的页面生成缩略图,放到HomeEditView中进行显示CellLayout view = (CellLayout) mWorkspace.getChildAt(i);ImageView image = new ImageView(this);Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);//绘制              final Canvas c = new Canvas(bitmap);              //设置比例              view.dispatchDraw(c);               image.setImageBitmap(bitmap);  image.setBackgroundColor(Color.GRAY);// 通过id判断是否可以删除if (((ViewGroup) view.getChildAt(0)).getChildCount() != 0) {image.setId(1);} else {image.setId(0);}views.add(image);}mDragGrid.addViews(views);mDragGrid.setBackgroundColor(Color.RED);mDragGrid.setVisibility(View.VISIBLE);mWorkspace.setVisibility(View.INVISIBLE); mHotseat.setVisibility(View.GONE);mSearchDropTargetBar.setVisibility(View.GONE);mDockDivider.setVisibility(View.GONE);    }    private OnClickPageListener listener = new OnClickPageListener() {@Overridepublic void onClickPage(int index, List<PageInfo> pages) {Log.d(TAG, "onClickPage");mWorkspace.setVisibility(View.VISIBLE); mHotseat.setVisibility(View.VISIBLE);mSearchDropTargetBar.setVisibility(View.VISIBLE);mDockDivider.setVisibility(View.VISIBLE);mDragGrid.setVisibility(View.GONE);mWorkspace.reorderChildren(pages);}};

4、Workspace.java中重新排列CellLayout代码

// 页面编辑完成后,重新排列CellLayout    public void reorderChildren(List<PageInfo> pages) {    List<View> views = removeOldViews();    View[] newViews = new View[pages.size()];        for (int i = 0; i < newViews.length; i++) {    PageInfo info = pages.get(i);    if (info.originPage != -1) {    newViews[i] = views.get(info.originPage);        // 更新此页面上的item的screen信息    CellLayout cell = (CellLayout) newViews[i];    CellLayoutChildren chi = (CellLayoutChildren) cell.getChildAt(0);    for (int j = 0; j < chi.getChildCount(); j++) {    ItemInfo in = (ItemInfo) chi.getChildAt(j).getTag();    // 设定新的screen    in.screen = i;    LauncherModel.updateItemInDatabase(getContext(), in);    }        } else {    newViews[i] = new CellLayout(mLauncher);    }    }        for (int i = 0; i < newViews.length; i++) {    addView(newViews[i]);    }        requestLayout();    }        private List<View> removeOldViews() {    List<View> list = new ArrayList<View>();    for (int i = 0; i < getChildCount(); i++) {    View view = getChildAt(i);    list.add(view);    }        for (View view : list) {    removeView(view);    }        return list;    }

5、Workspace.java中初始化CellLayout代码, 此方法最好在构造方法中调initWorkspace()方法的前一行调用(没搞明白,一开始就调用的话会出问题)

private void initCells(Context context) {    SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());    int count = sp.getInt("screen_count", 5);        for (int i = 0; i < count; i++) {    CellLayout cl = new CellLayout(context);        this.addView(cl);    }    }

6、CellLayout.java的单个参数的构造方法要改

public CellLayout(Context context) {super(context);// A ViewGroup usually does not draw, but CellLayout needs to draw a// rectangle to show// the user where a dragged item will land when dropped.setWillNotDraw(false);mOriginalCellWidth = mCellWidth = getResources().getDimensionPixelSize(R.dimen.workspace_cell_width);mOriginalCellHeight = mCellHeight = getResources().getDimensionPixelSize(R.dimen.workspace_cell_height);mWidthGap = mOriginalWidthGap = getResources().getDimensionPixelSize(R.dimen.workspace_width_gap);mHeightGap = mOriginalHeightGap = getResources().getDimensionPixelSize(R.dimen.workspace_height_gap);mMaxGap = getResources().getDimensionPixelSize(R.dimen.workspace_max_gap);setPadding(getResources().getDimensionPixelSize(R.dimen.workspace_left_padding),getResources().getDimensionPixelSize(R.dimen.workspace_top_padding),getResources().getDimensionPixelSize(R.dimen.workspace_right_padding),getResources().getDimensionPixelSize(R.dimen.workspace_bottom_padding));mCountX = LauncherModel.getCellCountX();mCountY = LauncherModel.getCellCountY();mOccupied = new boolean[mCountX][mCountY];setAlwaysDrawnWithCacheEnabled(false);final Resources res = getResources();mNormalBackground = res.getDrawable(R.drawable.homescreen_blue_normal_holo);mActiveGlowBackground = res.getDrawable(R.drawable.homescreen_blue_strong_holo);mOverScrollLeft = res.getDrawable(R.drawable.overscroll_glow_left);mOverScrollRight = res.getDrawable(R.drawable.overscroll_glow_right);mForegroundPadding = res.getDimensionPixelSize(R.dimen.workspace_overscroll_drawable_padding);mNormalBackground.setFilterBitmap(true);mActiveGlowBackground.setFilterBitmap(true);// Initialize the data structures used for the drag visualization.mCrosshairsDrawable = res.getDrawable(R.drawable.gardening_crosshairs);mEaseOutInterpolator = new DecelerateInterpolator(2.5f); // Quint ease// out// Set up the animation for fading the crosshairs in and outint animDuration = res.getInteger(R.integer.config_crosshairsFadeInTime);mCrosshairsAnimator = new InterruptibleInOutAnimator(animDuration,0.0f, 1.0f);mCrosshairsAnimator.getAnimator().addUpdateListener(new AnimatorUpdateListener() {public void onAnimationUpdate(ValueAnimator animation) {mCrosshairsVisibility = ((Float) animation.getAnimatedValue()).floatValue();invalidate();}});mCrosshairsAnimator.getAnimator().setInterpolator(mEaseOutInterpolator);mDragCell[0] = mDragCell[1] = -1;for (int i = 0; i < mDragOutlines.length; i++) {mDragOutlines[i] = new Point(-1, -1);}// When dragging things around the home screens, we show a green outline// of// where the item will land. The outlines gradually fade out, leaving a// trail// behind the drag path.// Set up all the animations that are used to implement this fading.final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);final float fromAlphaValue = 0;final float toAlphaValue = (float) res.getInteger(R.integer.config_dragOutlineMaxAlpha);Arrays.fill(mDragOutlineAlphas, fromAlphaValue);for (int i = 0; i < mDragOutlineAnims.length; i++) {final InterruptibleInOutAnimator anim = new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);anim.getAnimator().setInterpolator(mEaseOutInterpolator);final int thisIndex = i;anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {public void onAnimationUpdate(ValueAnimator animation) {final Bitmap outline = (Bitmap) anim.getTag();// If an animation is started and then stopped very quickly,// we can still// get spurious updates we've cleared the tag. Guard against// this.if (outline == null) {if (false) {Object val = animation.getAnimatedValue();Log.d(TAG, "anim " + thisIndex + " update: " + val+ ", isStopped " + anim.isStopped());}// Try to prevent it from continuing to runanimation.cancel();} else {mDragOutlineAlphas[thisIndex] = (Float) animation.getAnimatedValue();final int left = mDragOutlines[thisIndex].x;final int top = mDragOutlines[thisIndex].y;CellLayout.this.invalidate(left, top,left + outline.getWidth(),top + outline.getHeight());}}});// The animation holds a reference to the drag outline bitmap as// long is it's// running. This way the bitmap can be GCed when the animations are// complete.anim.getAnimator().addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {if ((Float) ((ValueAnimator) animation).getAnimatedValue() == 0f) {anim.setTag(null);}}});mDragOutlineAnims[i] = anim;}mBackgroundRect = new Rect();mForegroundRect = new Rect();mChildren = new CellLayoutChildren(context);mChildren.setCellDimensions(mCellWidth, mCellHeight, mWidthGap,mHeightGap);addView(mChildren);setBackgroundColor(Color.BLUE);}

7、PageInfo.java

public class PageInfo implements Comparable<PageInfo> {// 未编辑前是哪个页面public int originPage = -1;// 编辑完成后是哪个页面public int currentPage = -1;@Overridepublic int compareTo(PageInfo another) {return currentPage - another.currentPage;}}


最后来一张手机测的效果图





还有好多地方没有完善:1、设置主页       2、固定大小(可以改成固定dip)、因为布局不平均自适应可能不行  等等。。。





原创粉丝点击