View基础概念
位置参数
- top、left、right、bottom
大小均是基于父容器的左或上的距离,由此可计算View自身的宽高 - translationX、translationY
Android3.0后新增加的,相对父容器的偏移量,属性动画改变的就是这类的参数
通过get/set方法调用
View在平移过程中改变的是偏移量
MotionEvent相关方法
getX、getY
相对于当前View左上角的x、y坐标getRawX、getRawY
相对于手机屏幕左上角的x、y坐标ViewConfiguration
// 获取系统能识别的被认为是滑动的最小距离
ViewConfiguration.get(getContext()).getScaledTouchSlop();
// 允许Fling手势动作的最小值
ViewConfiguration.get(getContext()).getScaledMinimumFlingVelocity();
// 允许Fling手势动作的最大值
ViewConfiguration.get(getContext()).getScaledMaximumFlingVelocity();-
GestureDetector
手势识别
GestureDetector mGestureDetector = new GestureDetector(getApplicationContext(), this);
// 解决长按屏幕无法拖动
mGestureDetector.setIsLongpressEnabled(false);
// 触摸屏幕时
@Override
public boolean onDown(MotionEvent e) {
return false;
}// 手指在屏幕上按下,且未移动和松开时 @Override public void onShowPress(MotionEvent e) { } // 点击屏幕时 @Override public boolean onSingleTapUp(MotionEvent e) { return false; } // 手指在屏幕上滚动时 @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } // 手指长按时 @Override public void onLongPress(MotionEvent e) { } // 手指快速滑动时,此时也会不断调用onScroll @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return false; }
Activity事件托管给GestureDetector
@Override
public boolean onTouchEvent(MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
View事件托管给GestureDetector
mButton.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View arg0, MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
});
- VelocityTracker
速度追踪
if(mVelocityTracker == null){
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
一段时间内手指滑过的像素数,下面是1000毫秒滑动的速度
// 设置单位
mVelocityTracker.computeCurrentVelocity(1000);
// 获取1秒内x方向滑动像素
int xVelocity = (int) mVelocityTracker.getXVelocity();
重置和回收的方法
mVelocityTracker.clear();
mVelocityTracker.recycle();
View的滑动
按正常理解,在屏幕坐标系中,向右滑动为正,向左滑动为左
- scrollTo/scrollBy
Scroller滑动方式只能滑动内容
实际scrollTo/scrollBy滑动时相反
View左边缘在内容的右边时为正
View上边缘在内容的下边时为正
Scroller mScroller = new Scroller(mContext);
// 开始位置—>终点位置、时间
mScroller.startScroll(getScrollX(), 0, dx, 0, 500);
private void smoothScrollTo(int destX, int destY){
int scrollX = getScrollX();
int deltaX = destX - scrollX;
// 滑动的位置-当前位置就是1000ms内滑动的距离
mScroller.startScroll(scrollX, 0, deltaX, 0, 1000);
invalidate();
}
@Override
public void computeScroll(){
if(mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
invalidate方法导致View重绘,draw方法会调用computeScroll方法
computeScrollOffset方法获取scrollX和scrollY,就是当前应该滑动到的新位置
通过scrollTo方法来滑动
整个原理就是插值器通过通过时间流逝百分比计算出当前属性值改变百分比,再通过估值器计算出改变后具体的属性值
上面的过程就会实现弹性滑动,就是将一次大的滑动分成若干次小的滑动
- 动画
ObjectAnimator.ofFloat(view, "translationX", 0, 100).setDuration(100).start(); - LayoutParams布局参数
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)button.getLayoutParams();
params.width += 100;
params.leftMargin += 100;
// 两种设置方式
// button.setLayoutParams(params);
// button.requestLayout();
View弹性滑动
- Scroller
使用Scroller,View普通滑动已经总结了。主要是配合computeScroll方法的使用 - 动画
动画本身就具备这样的功能,可以通过ObjectAnimator或ValueAnimator实现
ValueAnimator animator = ValueAnimator.ofFloat(0, 1).setDuration(200);
animator.addUpdateListener(new AnimatorUpdateListener(){
@Override
public void onAnimationUpdate(ValueAnimator animator){
// 根据时间流逝得到值的百分比
int fraction = (int)animator.getAnimatedFraction();
mButton.scrollTo(startX + deltaX * fraction, 0);
}
});
动画在这里只提供当前值百分比计算,与Scroller类似
-
延时实现分段滑动
比如距离100像素,时间1000毫秒,分30次小的滑动,每次滑动延时30毫秒
private View view;
private int mCount = 0;
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
mCount++;
if(mCount <= 30){
// 分30次,计算每次移动的位置
float fraction = mCount/30.0f;
int scrollX = (int) (fraction * 100);
view.scrollTo(-scrollX, 0);
handler.sendEmptyMessageDelayed(0, 30);
}} }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); view = findViewById(R.id.text_view); handler.sendEmptyMessageDelayed(0, 5000); }
这里scrollTo滑动的只是View的内容,不是自身