【Android】Android View的滑动实现

        首先,了解触控事件对象MotionEent中封装的一些常用变量:

//单点触摸按下动作
public static final int ACTION_DOWN = 0;
//单点触摸离开动作
public static final int ACTION_UP = 1;
//触摸点移动动作
public static final int ACTION_MOVE = 2;
//触摸动作取消
public static final int ACTION_CANCEL = 3;
//触摸动作超出边界
public static final int ACTION_OUTSIDE = 4;
//多点触摸按下动作
public static final int ACTION_POINTER_DOWN = 5;
//多点离开动作
public static final int ACTION_POINTER_UP = 6;

        再来,了解获取坐标值的各种方法:


(图片转自http://www.linuxidc.com/Linux/2015-11/125391.htm)

        其中,View 提供的获取坐标方法有:

getTop(): 获取到的是View自身的顶边到其父布局顶边的距离

getLeft(): 获取到的是View自身的左边到其父布局左边的距离

getRight():获取到的是View自身的右边到其父布局右边的距离

getBottom():获取到的是View自身的底部到其父布局底部的距离

        MotionEent 提供的方法有:

getX(): 获取点击事件距离控件左边的距离,即视图坐标

getY(): 获取点击事件距离控件顶边的距离,即视图坐标

getRawX(): 获取点击事件距离整个屏幕左边的距离,即绝对坐标

getRawY(): 获取点击事件距离整个屏幕顶边的距离,即绝对坐标


        项目结构:

布局结构:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <com.example.scrolltest.widget.MyTextView 
        android:id="@+id/tv"
        android:layout_width="65dp"
        android:layout_height="65dp"
        android:background="#949494"
        />

</RelativeLayout>

MainActivity.java

package com.example.scrolltest;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends Activity {

	private TextView tv;

	int lastX = 0;
	int lastY = 0;
	int offsetX = 0;
	int offsetY = 0;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		tv = (TextView) findViewById(R.id.tv);
	}
}

MyTextView.java

<span style="font-size:12px;">package com.example.scrolltest.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;
import android.widget.TextView;

/**
 * 一个自定义TextView
 * 通过方法一 二 三实现拖拽滑动
 * 当手指放开时通过方法四实现平滑滑动到原来位置
 */
public class MyTextView extends TextView{
	
	private Scroller scroller;
	
	public MyTextView(Context context) {
		super(context);
	}

	public MyTextView(Context context, AttributeSet attrs) {
		super(context, attrs);
		scroller = new Scroller(getContext());
	}
	
	//按下时的坐标
	int lastX = 0;
	int lastY = 0;
	//滑动时产生的偏移量
	int offsetX = 0;
	int offsetY = 0;
	@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:
			offsetX = x - lastX;
			offsetY = y - lastY;
			Log.d("Lutext", "offsetX = " + offsetX);
			//方法一:监听触摸滑动,每次滑动调用layout方法重新对View布局
//			layout(getLeft() + offsetX, 
//					getTop() + offsetY, 
//					getRight() + offsetX,
//					getBottom() + offsetY);
			
			//方法二:相当于系统提供地一个对左右 上下移动的API封装
//			offsetLeftAndRight(offsetX);
//			offsetTopAndBottom(offsetY);
			
			//方法三:scrollTo scrollBy移动的是View的content,必须在ViewGroup中使用,才能移动子View
			//这里其实移动的就是ViewGroup,所以偏移值为负数,即将ViewGroup向左移动3单位,则结果为子View向右移动3单位
			//原文:想象手机屏幕是一个中空地盖板,盖板下面是一个巨大地画布,也就是我们想要显示的视图。当把这个盖板盖在画布上的某一处时,透过中间空的矩形,我们看见了手机屏幕上显示的视图,而画布上其他地方的视图,则被盖板盖住栏无法看见
			((View)getParent()).scrollBy(-offsetX, -offsetY);
			break;
			
		case MotionEvent.ACTION_UP:
			//方法四:Scroller
			//步骤一:通过自定义View的构造方法来创建一个Scroller对象
			//步骤二:重写computeScroll()方法,实现模拟滑动
			//步骤三:通过scroller.startScroll开启模拟过程
			View viewGroup = (View) getParent();
			//手指离开时,执行scroller的滑动过程,必须是通过scrollby/scrollto滑动时才有效
			scroller.startScroll(
					//getScrollX/Y 获取子View的移动距离
					viewGroup.getScrollX(),
					viewGroup.getScrollY(), 
					-viewGroup.getScrollX(),
					-viewGroup.getScrollY(), 5000);
			Log.d("Lutext", "ACTION_UP");
			Log.d("Lutext", "viewGroup.getScrollX() = " + viewGroup.getScrollX());
			invalidate();
			break;

		default:
			break;
		}
		return true;
	}
	
	/* 
	 * @see android.widget.TextView#computeScroll()
	 *     只能在此方法中获取模拟过程中的scrollX和scrollY坐标
	 * 但computeScroll()方法是不会自动调用的,
	 * 只能通过invalidate() -> draw() -> computeScroll()
	 * 来间接调用computeScroll()方法,所以要在此方法中调用invalidate()
	 * 实现循环获取scrollX和scrollY的目的
	 *     当模拟过程结束后,scroller.computeScrollOffset()返回false,
	 * 从而中断循环,完成整个平滑的过程
	 *     此方法实际使用的就是scrollTo方法
	 */
	@Override
	public void computeScroll() {
		super.computeScroll();
		//判断Scroller是否完成整个滑动
		if(scroller.computeScrollOffset()) {
			((View)getParent()).scrollTo(
					//getCurrX/Y 获得当前滑动坐标
					scroller.getCurrX(), 
					scroller.getCurrY());
			//通过重绘来循环调用computeScroll
			invalidate();
		}
	}

}</span>




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值