此博客主要介绍基本View滑动的实现方法,主要方法如下:
1、利用ScrollBy/ScrollTo方法实现;
2、利用动画的方法实现;
3、通过更改View的LayoutParams的属性值来实现。
View滑动的重要性:掌握滑动的方法是实现绚丽的自定义控件的基础。
一、利用ScrollTo/ScrollBy方法实现View的滑动
首先我们要明白View内部的两个属性mScrollX、mScrollY的值的改变规则,如下:
如上图所示,mScrollX = x1-x2,即起始位置的横坐标减去末位置的横坐标;mScrollY = y1 - y2,即起始位置的纵坐标减去末位置的纵坐标。
然后需要知道MotionEvent对象中有两组方法:getX()/getY()和getRawX()/getRawY(),它们的区别:getX()/getY()返回的是相对于当前View左上角的x和y坐标,而getRawX()和getRawY()返回的是相对于手机屏幕左上角的x和y坐标。
其次ScrollTo/ScrollBy方法只能滑动该View的内部控件(内容),如:LinearLayout布局中有一个ImageView,当给LinearLayout.scrollTo(….)的时候,滑动的是ImageView,如果该Linearlayout中有多个控件,那么这些控件就一起滑动。
最后写个demo,如下:
布局文件:scroll_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/scroll_text_view"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="利用ScrollTo/ScrollBy实现View的滑动"
android:textColor="#ffffff"
android:textSize="18sp"
android:background="#f7aa03"
android:gravity="center"
/>
<LinearLayout
android:id="@+id/scroll_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<ImageView
android:id="@+id/scroll_image_view"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@mipmap/ic_launcher"
android:background="#f20905"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="80dp"
android:text="测试text"
android:gravity="center"
android:textColor="#000"
android:background="#14d935"
/>
</LinearLayout>
</LinearLayout>
逻辑代码:ScrollActivity.java
public class ScrollActivity extends Activity {
private LinearLayout scrollLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.scroll_layout);
initView();
}
private void initView() {
scrollLayout = (LinearLayout) findViewById(R.id.scroll_layout);
scrollLayout.setOnTouchListener(new View.OnTouchListener() {
//每次移动的起始位置
float x;
float y;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//初始化起始位置
x = event.getX();
y = event.getY();
break;
case MotionEvent.ACTION_MOVE:
//当前的位置
float mX = event.getX();
float mY = event.getY();
//移动的距离
int dx = (int) (x - mX);
int dy = (int) (y - mY);
scrollLayout.scrollBy(dx, dy);
//重置起始位置
x = mX;
y = mY;
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return true;
}
});
}
}
这部分代码使用ScrollBy()方法实现的,我们还可以用ScrollTo()来实现,就是把上述的scrollLayout.setOnTouchListener()这段代码换成下面的代码即可:
scrollLayout.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
//控件的末位置
int x = (int)event.getX();
int y = (int)event.getY();
scrollLayout.scrollTo(-x, -y);
break;
case MotionEvent.ACTION_UP:
break;
default:
break;
}
return true;
}
});
对比ScrollBy()和ScrollTo()方法:
ScrollTo()在滑动到时候,手指按到的部位始终是滑动控件到左上角,体验不是很好;而ScrollBy()方法就不一样了,手指点哪儿就是那儿。
二、利用动画实现View的滑动
demo:
在一个界面中有一个按钮button,一个ImageView,button控制ImageView的滑动,如下:
animationButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//意思是从起始位置平移500像素
ObjectAnimator.ofFloat(animationImageView,"translationX",0,500).setDuration(100).start();
}
});
如上代码中,animationButton控制着animationImageView的平移。在动画中还可以做很多酷炫的滑动,详情会在后续博客中介绍。
三、通过更改View的LayoutParams的参数值来滑动
详情请看代码
public class ParamsActivity extends Activity {
private ImageView paramsImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.params_layout);
initView();
}
private void initView() {
paramsImageView = (ImageView) findViewById(R.id.params_image_view);
paramsImageView.setOnTouchListener(new View.OnTouchListener() {
//手指按下去的坐标
float x;
float y;
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//初始化手指坐标
x = event.getRawX();
y = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
//移动的坐标,
float mx = event.getRawX();
float my = event.getRawY();
//移动的距离
int dx = (int) (mx - x);
int dy = (int) (my - y);
//滑动View
setParamsImageViewLayoutParams(dx, dy);
//重置手指的坐标
x = mx;
y = my;
break;
default:
break;
}
return true;
}
});
}
private void setParamsImageViewLayoutParams(int dx, int dy) {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) paramsImageView.getLayoutParams();
params.leftMargin += dx;
params.topMargin += dy;
paramsImageView.requestLayout();
}
}
注意:
0、我在计算移动距离时,是用末位置的坐标减去起始位置的坐标;
1、我是利用event.getRawX()/event.getRawY()来获取坐标的,因为如果利用getX()/getY()的时候,当手指滑动的时候,View总是慢了一拍,不灵活;而getRawX()/getRawY()就紧跟手指移动,很灵活。
2、在更改LayoutParams参数时,我只是更改了leftMargin和topMargin的值,那能不能通过更改rightMargin和bottomMargin 的值来滑动View呢?答案是不能的,原因应该是控件从左上角开始,本来就跟父布局的右边、底部就有很大的距离,当设置的rightMargin和bottomMargin小于这个距离时,就不起作用了,所以最好去设置leftMargin和bottomMargin。
总结:
1、ScrollBy/ScrollTo是只能移动View内部的内容,即如果给一个View设置了scrollTo/scrollBy,则只能移动该View内部的控件,且View内部的控件一起移动;
2、我用的动画是属性动画,它可以规定在一定的时间内完成,在用的时候,最好是有一个触发的信息;
3、通过更改LayoutParams参数值的方法比较好(个人感觉),它跟scrollTo方法不同,它移动的就是它本身,即如果给一个View设置了onTouchListener,然后在其中移动事件,改变该View的params参数值,就可实现滑动的效果,切记获取坐标时,用getRawX。