您的位置:首页 > 其它

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

2012-10-15 11:16 459 查看
上一篇文章中我们了解了一下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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐