第三章 view的事件体系 ----- view滑动/拖动
程序员文章站
2022-05-05 10:25:43
...
Android view的滑动
先看下view完整代码如下:
public class DemoView extends View {
private int lastX;
private int lastY;
private Scroller mScroller;
public DemoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public DemoView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
}
public DemoView(Context context) {
super(context);
mScroller = new Scroller(context);
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()){
((View) getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
postInvalidate();
}
super.computeScroll();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//获取到手指处的横坐标和纵坐标
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
//计算移动的距离
int offsetX = x - lastX;
int offsetY = y - lastY;
//调用layout方法来重新放置它的位置
// layout(getLeft() + offsetX, getTop() + offsetY,
// getRight() + offsetX, getBottom() + offsetY);
//通过translation来实现
// int translationX = (int) getTranslationX() + offsetX;
// int translationY = (int) getTranslationY() + offsetY;
// setTranslationX(translationX);
// setTranslationY(translationY);
//通过layout param 实现 需要注意:如果view在布局文件中设置了layout_above、center等类似属性,则会出现问题
// RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
// layoutParams.leftMargin = getLeft() + offsetX;
// layoutParams.topMargin = getTop() + offsetY;
// setLayoutParams(layoutParams);
//通过MarginLayoutParams
// ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
// layoutParams.leftMargin = getLeft() + offsetX; //这样也可以
// layoutParams.topMargin = getTop() + offsetY;
// layoutParams.leftMargin += offsetX;
// layoutParams.topMargin += offsetY;
// setLayoutParams(layoutParams);
/*通过scrollBy操作,getParent是因为scrollBy是对view的内容进行移动,而不是对view本身移动
所以,当前view的移动通过获取父布局,对父布局进行scrollBy操作,当前view就是父布局的内容
note:scrollBy会对view的所有内容进行移动,如果父布局中还有其他的view(button啊 TextView啊)
则在拖动该view时其他view也会一起移动*/
((View) getParent()).scrollBy(-offsetX,- offsetY);
break;
}
return true;
}
public void smoothScrollTo(int destX,int destY){
int scrollX = getScrollX();
int scrollY = getScrollY();
int deltaX = destX - scrollX;
int deltaY = destY - scrollY;
//1000秒内滑向destX destY
Log.d("xj", "smoothScrollTo: ");
mScroller.startScroll(scrollX,scrollY,deltaX,deltaY,1000);
postInvalidate();// invalidate();
}
}
一、通过layout方法实现
- case MotionEvent.ACTION_MOVE: 下的代码如下:
//调用layout方法来重新放置它的位置
layout(getLeft() + offsetX, getTop() + offsetY,
getRight() + offsetX, getBottom() + offsetY);
二、offsetLeftAndRight()offsetTopAndBottom()
- case MotionEvent.ACTION_MOVE: 下的代码如下:
//调用offset方法来重新放置它的位置,
offsetLeftAndRight(offX);
offsetTopAndBottom(offY);
三、通过translation(动画的方式)来实现
- case MotionEvent.ACTION_MOVE: 下的代码如下:
//通过translation来实现
int translationX = (int) getTranslationX() + offsetX;
int translationY = (int) getTranslationY() + offsetY;
setTranslationX(translationX);
setTranslationY(translationY);
- 不随手指移动,仅实现view的滑动,使用属性动画(若要兼容3.0以下版本,需要使用开源动画库nineoldandroids)动画开源库:
ObjectAnimator.ofFloat(demoview,"translationX",0,300).setDuration(1000).start();
-使用view动画滑动,R.anim.translate为动画资源文件:
demoview.setAnimation(AnimationUtils.loadAnimation(this, R.anim.translate));
四、通过LayoutParams来实现
如果view在布局文件中设置了layout_above、center(因文中使用了相对布局)等类似属性,则会出现问题,不会正常拖动
- case MotionEvent.ACTION_MOVE: 下的代码如下:
/*通过LayoutParams来实现,这里父布局使用的是RelativeLayout,因此使用RelativeLayout.LayoutParams,若父布局是LinearLayout,则使用RelativeLayout.LayoutParams*/
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getTop() + offsetY;
setLayoutParams(layoutParams);
还可以使用通过MarginLayoutParams实现,代码替换为:
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
//下面两种写法:使用一种即可
//方法一(注释中)
//layoutParams.leftMargin = getLeft() + offsetX;
//layoutParams.topMargin = getTop() + offsetY;
//方法二
layoutParams.leftMargin += offsetX;
layoutParams.topMargin += offsetY;
setLayoutParams(layoutParams);
五、通过scollTo与scollBy(动画的方式)来实现
sceollTo(x,y) 绝对滑动,传入的是移动的终点坐标
scrollBy(dx,dy) 相对滑动,传入的是移动的增量,
通过scrollBy传入的值应该是你需要的那个增量的相反数!
通过scrollBy操作,getParent是因为scrollBy是对view的内容进行移动,而不是对view本身移动,所以,当前view的移动通过获取父布局,对父布局进行scrollBy操作,当前view就是父布局的内容
note:scrollBy会对view的所有内容进行移动,如果父布局中还有其他的view(button啊 TextView啊,则在拖动该view时其他view也会一起移动
- case MotionEvent.ACTION_MOVE: 下的代码如下:
//通过scrollBy来实现
((View) getParent()).scrollBy(-offsetX,- offsetY);
六、通过Scroller(弹性滑动)来实现
这个是滑动效果,不是随着手指拖动效果
- 初始化Scroller
public DemoView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
}
- 重写computeScroll()方法,
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()){
((View) getParent()).scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
// postInvalidate();//这个也可以,效果上没啥区别
invalidate();
}
}
- 调用Scroller.startScroll()方法。写一个smoothScrollTo()方法来调用Scroller.startScroll()方法,实现滑动
public void smoothScrollTo(int destX,int destY){
int scrollX = getScrollX();
int scrollY = getScrollY();
int deltaX = destX - scrollX;
int deltaY = destY - scrollY;
//2000秒内滑动到指定点
mScroller.startScroll(scrollX,scrollY,deltaX,deltaY,2000
//postInvalidate();//这个也可以,效果上没啥区别
invalidate();
}
- 在activity中调用该方法,注意:该方法移动的是demoView所在父布局中的所用内容
demoView.smoothScrollTo(-500,-300);
- computeScrollOffset方法判断是否完成了整个滑动,返回true,则没有完成,否则完成滑动。
- 必须要用invalidate方法刷新,因为computeScroll方法不会自动调用,它是在view的draw方法中被调用的,所以必须使用invalidate刷新。
- 在startScroll中,偏移量跟使用scrollBy方法中的偏移量用法是一样的,即也必须填写你实际想要移动距离的相反数。也就是你实际想让它偏移一个正值,这里就填写它相应的负值,如果想偏移一个负值,这里就填写相应的正值!
- 通过Scroller实现弹性滑动的代码基本是固定的,实现原理:
startScroll方法下面的invalidate方法会让view进行重绘,view进行重绘时draw方法又会去调用computeScroll方法,该方法在view中是一个空实现,需要我们自己实现。computeScroll方法会向Scroller获取当前的scrollX和scrollY,然后通过scrollTo方法滑动;接着又调用了invalidate方法重绘,重复之前的动作,直到整个滑动结束。
总结
- 其中一二三四五都是view随手指可以移动
- scrollTo 和scrollBy 操作简单,适合对view内容滑动
- 动画:适用于没有交互的view和实现复杂的动画效果
- 改变布局参数:操作稍微复杂,适用于有交互的view
- 参考文章,书籍,Android开发艺术探索
上一篇: CAS单点登录3--服务端登录页个性化
下一篇: Linux的SWAP分区