基础知识准备:
一、在View内部,和滚动相关的类有以下两个
public void scrollTo(int x, int y)
说明:在当前视图内容偏移至(x , y)坐标处,即显示(可视)区域位于(x , y)坐标处。
方法原型为: View.java类中
public void scrollBy(int x, int y)
说明:在当前视图内容继续偏移(x , y)个单位,显示(可视)区域也跟着偏移(x,y)个单位。
使用:
scrollTo,将view的左上角(x,y)为标准点进行移动。 调用scrollTo(10, 10)表示将View中的内容移动到x = 10, y = 10的位置
public void scrollBy(int x, int y) { scrollTo(mScrollX + x, mScrollY + y); }
此处,scrollBy(10,10),相当于scrollTo(x+10,y+10)
二、getScrollX()+getScrollY()
mScrollX:表示离视图起始位置的x水平方向的偏移量
mScrollY:表示离视图起始位置的y垂直方向的偏移量
分别通过getScrollX() 和getScrollY()方法获得。
注意:mScrollX和mScrollY指的并不是坐标,而是偏移量。
三、getX getRowX()getLeft()等方法
MotionEvent类中 getRowX()和 getX()的区别:
event.getRowX():触摸点相对于屏幕原点的x坐标
event.getX(): 触摸点相对于其所在组件原点的x坐标。意思就是说获取到实际的View的x y 值,该值也是相对父视图而言的,并且该值 getX = getLeft + getTraslationX。最后得出的值也是相对父视图来说的。
于是乎: view.getScrollY() + event.getY() 就得到了view中的触摸点在Y轴上的偏移量
getLeft , getTop, getBottom, getRight, 这一组是获取相对在它父亲里的坐标
四、刷新界面等值
invalidate()是用来刷新View的,必须是在UI线程中进行工作。比如在修改某个view的显示时,调用invalidate()才能看到重新绘制的界面。invalidate()的调用是把之前的旧的view从主UI线程队列中pop掉。
五、View执行过程
view的执行过程onDraw、onSizeChanged,onFinishInflate
在onSizeChanged中,可以获取view的一些位置信息
Demo:
package com.example.zoompro;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.BounceInterpolator;
import android.widget.OverScroller;
import android.widget.TextView;
public class MyJellyTextView extends TextView {
private float startX;
private float startY;
private float downY;
private float downX;
private OverScroller mScroller;
public MyJellyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new OverScroller(context, new BounceInterpolator());
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = event.getRawX();
downY = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
//获取在屏幕中的位置
int[] location = new int[2];
getLocationOnScreen(location);
int x = location[0];
int y = location[1];
//控制View的移动范围
if (x > MainActivity.screenWidth*3/5|| x < MainActivity.screenWidth/8) {
break;
}
if (y >MainActivity.screenHeigh*9/10 || y < MainActivity.screenHeigh/5) {
break;
}
float disX = event.getRawX() - downX;
float disY = event.getRawY() - downY;
// 移动 分方向
offsetLeftAndRight((int) disX);
offsetTopAndBottom((int) disY);
downX = event.getRawX();
downY = event.getRawY();
break;
case MotionEvent.ACTION_UP:
// 反弹回原来的位置
mScroller.startScroll((int) getX(), (int) getY(), -(int) (getX() - startX), -(int) (getY() - startY));
invalidate();//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果
break;
default:
break;
}
return super.onTouchEvent(event);
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
setX(mScroller.getCurrX());
setY(mScroller.getCurrY());
invalidate();
}
}
// view的执行过程onDraw、onSizeChanged,onFinishInflate
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
startX = getX();
startY = getY();
}
}