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

来源:互联网 发布:足球打水软件多少钱 编辑:程序博客网 时间:2024/05/22 15:57

  上一篇文章中我们了解了一下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()方法如下:

        @Overridepublic 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


原创粉丝点击