一 实现活动效果的核心
当触碰View时,系统记下当前触摸点的坐标,当手指移动时,系统记下移动后的触摸点的坐标,
从而获取 到相对于前一次坐标点的偏移量,并通过偏移量来修改View的坐标,这样不断重复
从而实现滑动的过程
二layout分法
在View 进行绘制时,会调用onLayout方法来设置显示的位置,同样可以通过修改View
的left,top,right,bottom四个属性来控制View的坐标,通过onTouchEvent()获取触摸点的坐标
计算偏移量
通过视图坐标系来获取偏移量
getX()
getY()
通过绝对坐标来获取偏移量
getRawY()
getRawY()
三 offSetLeftAndRight() 分法与offSetTobAndBottom()
相当于系统提供的一个对左右,上下移动的API的封装,当计算出偏移量后
四 layoutParams 要通过父容器获取到,如果没有放在这个父容器中是无法获取到的
Layoutparams 保存了一个View的布局参数,因此可以在程序中,通过改变LayoutParams
来动态的修改一个布局的位置参数. 当然,计算偏移量的方法与在Layout方法中计算offset也是一样 的.
当获取到偏移量之后,就可以通过setLayoutParams 来改变其LayoutParams.
五 scrollTo 与scollBy
1 scrollTo 与scrollBy 区别
在一个View中,系统提供了scrollTo ,scrollBy 两种方式来改变一个View的位置
这两个方法的区别非常好理解,与英文中的To和By的区别类似,
scrollTo(x,y) 表示移动到一个具体的坐标点(x,y)
而scrollBy(dx,dy)表示移动的增量为dx,dy
获取偏移量后使用scrollBy 来移动View 如下
int offsetX = x-lastX;
int offsetY = x - lastY;
scrollBy(offsetX,offsetY)
package com.yifei.myapplication;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class MyScrollView extends View {
private int lastX;
private int lastY;
public MyScrollView(Context context) {
super(context);
initView();
}
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView();
}
private void initView() {
setBackgroundColor(Color.RED);
}
@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;
//在当前left top right botton 的基础上加上偏移量
layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
break;
case MotionEvent.ACTION_UP://抬起
break;
default:
return false;
}
return true;
}
}
使用getRawX(), getRawY()
package com.yifei.myapplication;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class MyRawScrollView extends View {
private int lastX;
private int lastY;
public MyRawScrollView(Context context) {
super(context);
initView();
}
public MyRawScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public MyRawScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public MyRawScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView();
}
public void initView() {
setBackgroundColor(Color.BLUE);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int rawX = (int) event.getRawX();//获取触摸点坐标
int rawY= (int) event.getRawY(); //
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN://按下
//记录启始点坐标
lastX = rawX;
lastY = rawY;
break;
case MotionEvent.ACTION_MOVE://移动
int offsetX= rawX - lastX;
int offsetY = rawY - lastY;
//
layout(getLeft()+offsetX,getTop()+offsetY,getRight()+offsetX,getBottom()+offsetY);
//重新设置初始坐标
lastX = rawX;
lastY = rawY;
break;
case MotionEvent.ACTION_UP://抬起
break;
default:
return false;
}
return true;
}
}
offsetLeftAndRight(offsetX);
offsetTopAndBottom(offsetY);
在两句话是对
layout(getLeft()+offsetX,getTop()+offsetY,getRight()+offsetX,getBottom()+offsetY);
的简写
通过setLayoutParams()移动View
package com.yifei.myapplication;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
public class MyLayoutParamsView extends View {
private int lastX;
private int lastY;
public MyLayoutParamsView(Context context) {
super(context);
initView();
}
public MyLayoutParamsView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public MyLayoutParamsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public MyLayoutParamsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView();
}
private void initView() {
setBackgroundColor(Color.GREEN);
}
@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;
//获取布局的具体参数
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft()+offsetX;
layoutParams.topMargin = getTop() +offsetY;
setLayoutParams(layoutParams);
break;
case MotionEvent.ACTION_UP:
break;
default:
return false;
}
return true;
}
}
利用ViewGroup.MarginLayoutParams 来设定子元素的Margin 从而设置子元素的位置
package com.yifei.myapplication;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
public class MyLayoutParamsView extends View {
private int lastX;
private int lastY;
public MyLayoutParamsView(Context context) {
super(context);
initView();
}
public MyLayoutParamsView(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public MyLayoutParamsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public MyLayoutParamsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView();
}
private void initView() {
setBackgroundColor(Color.GREEN);
}
@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;
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
layoutParams.topMargin = offsetY+getTop();
layoutParams.leftMargin=offsetX+getLeft();
setLayoutParams(layoutParams);//把layout参数设置到父容器中
break;
case MotionEvent.ACTION_UP:
break;
default:
return false;
}
return true;
}
}