现在的位置: 首页 > 综合 > 正文

模拟Launcher中SliderView的滑动操作以及可随意拖动图片的实现

2013年10月03日 ⁄ 综合 ⁄ 共 7027字 ⁄ 字号 评论关闭

  上一篇文章中我们了解了一下ADW_Launcher的托盘中SliderView的滑动,我们详细分析了SliderView滑动的过程。文章地址:ADW_Launcher的托盘
——SliderView研究
。今天,我们就来模拟一下ADW_Launcher中SliderView的实现以及可随意拖动图片的实现(这里我们给出两种方式)。相信如果看过上一篇文章,制作这个效果是很简单的。不多说了,直接贴出效果图:

  先说一下文件的目录结构。总共涉及到四个类。MainActivity完成跳转,负责跳转到MyViewActivity。在MainActivity的点击事件中给相应的intent设置extra,值为需要给MyViewActivity设置的布局文件。在MyViewActivity使用LayoutInflater来填充这个布局文件,然后生成对应的view展示出来即可。MySliderView继承自ImageView,该类重写了onTouchEvent方法,对MySliderView的滑动事件做了处理。MyDragView也继承自ImageView,同样重写onTouchEvent方法,实现图片水平滑动,竖直滑动以及随意滑动。sliding_target_bottom.xml是一个动画文件,表示MySliderView下方滚动的箭头。tray_collapse.xml和tray.xml是图片选择器,对应的图片为格子和主页。drag.xml表示的是
可随意拖动的图片 部分的布局,里面放了一个MyDragView;slider.xml表示的是滑动托盘的布局,里面放了一个MySliderView。文件目录结构的截图如下:

一:模拟一下ADW_Launcher中SliderView的实现

下面就对MySliderView.java类做一个简单的说明。更详细的分析请看我的这边文章:ADW_Launcher的托盘 ——SliderView研究。里面有对SliderView代码的详细分析。

1、moveHandle()方法 我们只对竖直方向的滑动做处理。

   /**
     * 处理移动
     * @param x  左右滑动事件我们忽略
     * @param y
     * offsetTopAndBottom()是很关键的代码,作用是将当前view的mTop和mBottom的值重新设置,当调用
     * v.invalidate(rect);这句代码时将使用这个mTop和mBottom去重绘view(通过getTop()和getBottom()可以得到这两个值)
     */
    private void moveHandle(float x, float y) {
    	int deltaY=0;
        boolean moved=false;
        //如果触电的位置大于  托盘图片高度的一半时就可以滑动了(可以再模拟器上,将鼠标置于托盘的最顶端进行测试【要拖动一定的距离才可以滑动】)
        deltaY = (int) y- (getHeight() / 2);
        if((deltaY<0 && getTop()>mLimitRect.top) || (deltaY>0 && getBottom()<mLimitRect.bottom)){
        	//每次滑动之后,y值在变,每变一次就产生一个新的mTop和mBottom,然后再invalidate,也就实现了滑动的效果。
        	offsetTopAndBottom(deltaY);
        	moved=true;
        }
    	if(moved){
	        Rect rect=new Rect(getLeft() , getTop()-deltaY, getRight(), getBottom()-deltaY);
	        ViewGroup v=(ViewGroup)getParent();
	        v.invalidate(rect);
    	}
    }

2、dispatchTriggerEvent()方法。我们知道,在ADW_Launcher中,当用户滑动到SliderView到一定位置的时候,程序将执行该方法。这里,我们只是模拟,此处我们的操作是隐藏当前的控件并且给用户一个提示即可。

   /**
     * 模拟进入MiniLauncher,我们这里仅仅是托盘消失
     */
    private void dispatchTriggerEvent(int whichHandle) {
    	performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
    		    HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
    	this.setVisibility(View.GONE);
    	if(tv != null){
    		tv.setText("进入到了MiniLauncher");
    	}
        Toast.makeText(mContext, "托盘消失,进入MiniLauncher方式", 0).show();
    }

3、dispatchClickedEvent()方法。在ADW_Launcher中,用户点击SliderView将执行该方法,我们通过下面的代码来模拟。更换SliderView的图片,并且设置显示的文本信息。文本信息对应的TextView的控件的定义在createTargets()方法中。我们知道这个方法的作用是第一次点击SliderView的时候创建滑动的箭头。

createTargets()方法如下:它将创建往下滑动的箭头,这点是与ADW_Launcher中不同的地方,具体的代码请看DEMO中源代码。

private void createTargets(){
    	mTargets=new ArrayList<ImageView>();
    	LinearLayout p=(LinearLayout)getParent();

    	LinearLayout.LayoutParams lp=(LinearLayout.LayoutParams)getLayoutParams();
        final int horizontalGravity = Gravity.CENTER_HORIZONTAL;
        Starter starter=new Starter();//创建动画
        //我们只做往下的滑动箭头
		if(mSlideDirections == DIRECTIONS){
	    	ImageView v2 =new ImageView(getContext());
        	if(v2.getBackground()==null){
        		v2.setBackgroundResource(R.drawable.sliding_target_bottom);
        	}
			AnimationDrawable frameAnimation = (AnimationDrawable) v2.getBackground();
			starter.addAnimation(frameAnimation);
	    	v2.setTag(DIRECTIONS);
	    	//mTargets表示  动画箭头的区域
	    	mTargets.add(v2);
	    	lp=new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
	    	lp.gravity=horizontalGravity;
	    	lp.topMargin=getBottom()+mTargetDistance;
	    	p.addView(v2, lp);
	    	//托盘到箭头滑动动画的距离  frameAnimation.getIntrinsicHeight()得到的是动画的高度
	    	mLimitRect.bottom=getBottom()+mTargetDistance * 3+frameAnimation.getIntrinsicHeight()+securityMargin;
	    
	    	
	    	//增加一个TextView
	    	tv = new TextView(getContext());
	    	tv.setText("现在处于桌面");
	    	tv.setTextSize(25);
	    	lp=new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
	    	lp.gravity = horizontalGravity;
	    	lp.topMargin = 50;
	    	p.addView(tv,lp);
		}
		//将动画加入到消息队列
		post(starter);
    }

dispatchClickedEvent()方法如下:

   /**
     * 模拟点击,用户执行的是点击或者拖动托盘位置未达到进入MiniLauncher。
     */
    private void dispatchClickedEvent() {
    	if(isTray){
    		this.setBackgroundResource(R.drawable.tray_collapse);
    		if(tv != null){
        		tv.setText("现在处于应用程序列表页面");
        	}
    		isTray = false;
    	}else{
    		this.setBackgroundResource(R.drawable.tray);
    		if(tv != null){
        		tv.setText("现在处于桌面");
        	}
    		isTray = true;
    	}
    }

二:可随意拖动图片的实现

这个效果涉及到的类为 MyDragView.java。我们在它的onTouchEvent中设置ACTION_MOVE的事件处理。onTouchEvent()方法如下:

        @Override
	public boolean onTouchEvent(MotionEvent event) {
		
		int flag = event.getAction();
		int currentX = (int) event.getX();
		int currentY = (int) event.getY();
		System.out.println("currentX==" + currentX + ",currentY==" + currentY);
		
		switch (flag) {
		case MotionEvent.ACTION_DOWN:
			preX = currentX;
			preY = currentY;
			break;
		case MotionEvent.ACTION_MOVE:
			 moveHandler(currentX,currentY);//第一种方式
//			 moveHandler2(currentX,currentY);//第二种方式
//			 moveHandler3(currentX,currentY);//水平滑动
//			 moveHandler4(currentX,currentY);//竖直滑动
			break;
		case MotionEvent.ACTION_CANCEL:
			
			break;
		case MotionEvent.ACTION_UP:
			break;
		}
		return true;
	}

1、moveHandler()方法是用第一种滑动方式:记录控件开始的位置,没滑动一次都会产生一个偏移,使用原始位置的mLeft(距离父控件左边的距离),mTop,mRight,mBottom 加上各个方向上的偏移量得到新的mLeft,mTop,mRight,mBottom 值,然后调用view的layout方法,使用这四个值去绘制view。

       /**
	 * 第一种移动方式 重新layout
	 * @param x
	 * @param y
	 */
	private void moveHandler(int x,int y){
		int gapX = x - preX;
		int gapY = y - preY;
		int left = getLeft() + gapX;
		int top = getTop() + gapY;
		int right = getRight() + gapX;
		int bottom = getBottom() + gapY;
		if(left < 0){
			left = 0;
			right = getWidth();
		}
		if(top < 0){
			top = 0;
			bottom = getHeight();
		}
		if(right > w){
			left = w - getWidth();
			right = w;
		}
		if(bottom > h){
			top = h - getHeight();
			bottom = top + getHeight();
		}
		this.layout(left, top, right, bottom);
	}

2、moveHandler2()方法是第二种滑动方式:每次滑动产生偏移后,将各个方向的偏移通过offsetLeftAndRight()和offsetTopAndBottom()方法重新设置mLeft,mTop,mRight,mBottom 的值。然后得到父控件,让父控件调用invalidate()方法去重绘我们的子控件。

       /**
	 * 第二种移动方式  让父控件重绘需要重绘的部分
	 * @param x
	 * @param y
	 */
	private void moveHandler2(int x,int y){
		System.out.println("y==" + y + ",preY==" + preY + ",h==" + getHeight());
		int gapX = x - preX;
		int gapY = y - preY;
		int left = getLeft() + gapX;
		int top = getTop() + gapY;
		int right = getRight() + gapX;
		int bottom = getBottom() + gapY;
        if(left < 0 || right > w){
        	gapX = 0;
        }
        offsetLeftAndRight(gapX);
        if(top < 0 || bottom > h){
        	gapY = 0;
        }
        offsetTopAndBottom(gapY);
        // Rect实际上只是保证了一个固定大小的矩形区域而已。offsetLeftAndRight()代码会去改变
        //button的mLeft,mTop,mRight,mBottom等值.从而实现button的重绘。
        Rect rect=new Rect(getLeft()-gapX , getTop()-gapY, getRight()-gapX, getBottom()-gapY);
        //如果你要调用invalidate方法,需要调用父控件的invalidate方法。如果你仅仅调用当前view的invalidate
        //方法,上一个位置的view并不会被清除。
        ViewGroup v=(ViewGroup)getParent();
        v.invalidate(rect);
	}

3、moveHandler3()方法只处理水平方向的滑动:它的原理是,不管竖直方向有没有产生偏移,始终使用原始位置的mTop和mBottom值绘制view。这样出来的效果就竖直方向无法移动了。

       /**
	 * 只能在水平方法移动
	 * @param x
	 * @param y
	 */
	private void moveHandler3(int x,int y){
		int gapX = x - preX;
		int left = getLeft() + gapX;
		int right = getRight() + gapX;
        if(left < 0 || right > w){
        	gapX = 0;
        }
        offsetLeftAndRight(gapX);
        // Rect实际上只是保证了一个固定大小的矩形区域而已。offsetLeftAndRight()代码会去改变
        //button的mLeft,mTop,mRight,mBottom等值.从而实现button的重绘。
        Rect rect=new Rect(getLeft()-gapX , getTop(), getRight()-gapX, getBottom());
        ViewGroup v=(ViewGroup)getParent();
        v.invalidate(rect);
	}

4、moveHandler4()方法只处理竖直方向的滑动:它的原理是,不管水平方向有没有产生偏移,始终使用原始位置的mLeft和mRight值绘制view。这样出来的效果就是水平方法无法移动了。

       /**
	 * 只能在竖直方法移动
	 * @param x
	 * @param y
	 */
	private void moveHandler4(int x,int y){
		System.out.println("y==" + y + ",preY==" + preY + ",h==" + getHeight());
		int gapY = y - preY;
//		System.out.println("gapY==" + gapY);
		int top = getTop() + gapY;
		int bottom = getBottom() + gapY;
		if(top < 0){
			top = 0;
			bottom = getHeight();
		}
		if(bottom > h){
			top = h - getHeight();
			bottom = top + getHeight();
		}
		this.layout(getLeft(), top, getRight(), bottom);
	}

  至此,我们就成功模拟了ADW_Launcher的托盘中SliderView的滑动并且是实现了可随意滑动的图片的效果。本来这部分内容应该是放在这篇文章(ADW_Launcher的托盘
——SliderView研究
)中的,但是由于上篇文章内容过长,因此就单独移出来。好了,这部分内容就说到这里,有不懂的地方可以回帖一起讨论,不足的地方请指正,一同进步,谢谢。

DEMO下载地址:

http://download.csdn.net/detail/yanbin1079415046/4647851

抱歉!评论已关闭.