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


    最近研究页面删除,稍微总结一下,以后继续补充:

        本文主要讲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;
    	// 前当是不是在挪动view
    	private 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() {
    		
    		@Override
    		public 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, "-----------------------------");
    	}
    
    	@Override
    	public 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();
    		}
    	}
    	
    	// 当有页面被删除时,重新排列view
    	private 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);
    		}
    	}
    
    	// 重新排列view
    	private 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明说:最后的deleteZone
    		for (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;
    	}
    
    	// 挪动被拖曳的view
    	private 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);
    			}
    		}
    	}
    
    	@Override
    	protected 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;
    				}
    
    			}
    		}
    	}
    
    	@Override
    	protected 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;
    	}
    
    	@Override
    	public 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;
    	}
    
    	// 点击添加时、建创一个新view
    	private 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);
    	}
    	
    	// 建创表现在最后的添加view
    	private 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;
    	}
    
    	@Override
    	protected 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() {
    
    		@Override
    		public 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 out
    		int 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 run
    						animation.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() {
    				@Override
    				public 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;
    	
    	@Override
    	public int compareTo(PageInfo another) {
    		return currentPage - another.currentPage;
    	}
    }

        

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

        

        

        

        

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

        

        

        

        

    文章结束给大家分享下程序员的一些笑话语录: 一程序员告老还乡,想安度晚年,于是决定在书法上有所造诣。省略数字……,准备好文房4宝,挥起毛笔在白纸上郑重的写下:Hello World

  • 相关阅读:
    [POJ] 1979 Red and Black
    [Codeforces Round #192 (Div. 2)] D. Biridian Forest
    [Codeforces Round #192 (Div. 2)] B. Road Construction
    [Codeforces Round #192 (Div. 2)] A. Cakeminator
    430 vue组件命名方式: 短横线、驼峰
    429 vue脚手架
    428 webpack 使用步骤
    427 单页面应用,vue路由
    426 vue组件
    425 json-server,axios
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/3037389.html
Copyright © 2020-2023  润新知