ViewFlipper实现图片动态切换、GestureDetector实现手势捕捉


ViewFlipper是Android系统提供的用于切换图片的UI控件,而GestureDetector是Android提供的用于判断手势并执行相应操作的类,该类中手势判断的方法与传统的手势判断的方法(View类中的setOnTouchListener方法)相比,操作更加方便,提供的参数更多,可判断的手势更加多样。下面将浅析一个demo:使用GestureDetector的手势判断方法,动态实现切换ViewFlipper中的图片。


demo的实现效果

demo的实现效果如下所示——左右滑动屏幕上的图片,实现图片的轮询切换。
这里写图片描述这里写图片描述
注:由于切图速度比较快,故截图显示不够明了,下面将在代码中打印Log并说明手势方法的调用。


XML布局

XML布局使用了include标签用于包含相似的内容:

<ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/view_flipper"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <include
        android:id="@+id/screen1"
        layout="@layout/item1" />

    <include
        android:id="@+id/screen2"
        layout="@layout/item2" />

    <include
        android:id="@+id/screen3"
        layout="@layout/item3" />

    <include
        android:id="@+id/screen4"
        layout="@layout/item4" />

    <include
        android:id="@+id/screen5"
        layout="@layout/item5" />

</ViewFlipper>

item1的layout布局如下(item2-item5与item1相仿,此处不再列出):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/android1"
    android:orientation="vertical" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="view1" />

</LinearLayout>

activity逻辑实现

public class MainActivity extends Activity {

    public static final String TAG = "GESTURE_DETECTOR";
    private ViewFlipper mViewFlipper;

    private GestureDetector mGestureDetector;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mViewFlipper = (ViewFlipper) findViewById(R.id.view_flipper);
        // 初始化GestureDetector类
        mGestureDetector = new GestureDetector(this,
                new CustomSimpleOnGestureListener());

        // 依然需要实现setOnTouchListener方法
        mViewFlipper.setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                // 使用GestureDetector接管手势操作
                mGestureDetector.onTouchEvent(event);

                return true;
            }
        });

    }

    // 重写GestureDetector类中的静态子类SimpleOnGestureListener,
    // 并根据不同手势操作,有选择地重写该静态子类中的方法
    public class CustomSimpleOnGestureListener extends
            GestureDetector.SimpleOnGestureListener {

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            // TODO Auto-generated method stub
            Log.i(TAG, "--onSingleTapUp--");
            return super.onSingleTapUp(e);
        }

        @Override
        public void onLongPress(MotionEvent e) {
            // TODO Auto-generated method stub
            Log.i(TAG, "--onLongPress--");
            super.onLongPress(e);
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                float distanceX, float distanceY) {
            // TODO Auto-generated method stub
            Log.i(TAG, "--onScroll--");
            return super.onScroll(e1, e2, distanceX, distanceY);
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {
            // TODO Auto-generated method stub
            Log.i(TAG, "--onFling--");
            // 从左往右划 划到上一张
            if (e2.getX() - e1.getX() > 100) {
                mViewFlipper.setInAnimation(AnimationUtils.loadAnimation(
                        MainActivity.this, R.anim.show_previous_in));
                mViewFlipper.setOutAnimation(AnimationUtils.loadAnimation(
                        MainActivity.this, R.anim.show_previous_out));
                mViewFlipper.showPrevious();
            }
            // 从右往左划 划到下一张
            else if (e1.getX() - e2.getX() > 100) {
                mViewFlipper.setInAnimation(AnimationUtils.loadAnimation(
                        MainActivity.this, R.anim.show_next_in));
                mViewFlipper.setOutAnimation(AnimationUtils.loadAnimation(
                        MainActivity.this, R.anim.show_next_out));
                mViewFlipper.showNext();
            }

            return true;
        }

        @Override
        public void onShowPress(MotionEvent e) {
            // TODO Auto-generated method stub
            Log.i(TAG, "--onShowPress--");
            super.onShowPress(e);
        }

        @Override
        public boolean onDown(MotionEvent e) {
            // TODO Auto-generated method stub
            Log.i(TAG, "--onDown--");
            return super.onDown(e);
        }

        @Override
        public boolean onDoubleTap(MotionEvent e) {
            // TODO Auto-generated method stub
            Log.i(TAG, "--onDoubleTap--");
            return super.onDoubleTap(e);
        }

        @Override
        public boolean onDoubleTapEvent(MotionEvent e) {
            // TODO Auto-generated method stub
            Log.i(TAG, "--onDoubleTapEvent--");
            return super.onDoubleTapEvent(e);
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) {
            // TODO Auto-generated method stub
            Log.i(TAG, "--onSingleTapConfirmed--");
            return super.onSingleTapConfirmed(e);
        }

        @Override
        public boolean onContextClick(MotionEvent e) {
            // TODO Auto-generated method stub
            Log.i(TAG, "--onContextClick--");
            return super.onContextClick(e);
        }

    }
}

代码分析:

  • 根据代码可知,要通过GestureDetector实现手势操作,仍然要先实现View类中的setOnTouchListener方法并传入OnTouchListener接口对象,只是需要在该接口中的onTouch方法中使用GestureDetector的onTouchEvent方法接管手势操作而已。
  • 初始化GestureDetector类时,该类的构造方法中的第二个参数可以是以下4个对象之一:

    • 接口OnGestureListener,该接口中有6个未实现方法:
      —— onDown(MotionEvent e);
      —— onShowPress(MotionEvent e);
      —— onSingleTapUp(MotionEvent e);
      —— onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
      —— onLongPress(MotionEvent e);
      —— onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)

    • 接口OnDoubleTapListener,该接口中有3个未实现方法:
      —— onSingleTapConfirmed(MotionEvent e);
      —— onDoubleTap(MotionEvent e);
      —— onDoubleTapEvent(MotionEvent e);

    • 接口OnContextClickListener ,该接口中有1个未实现方法:
      —— onContextClick(MotionEvent e);
    • 静态子类SimpleOnGestureListener
      —— 该子类实现了上述3个接口的全部10个方法,只是都是空实现而已,并没有进行具体的逻辑覆盖。
  • 推荐使用静态子类SimpleOnGestureListener对象作为构造GestureDetector类的第二个参数,这样可以有选择地覆盖所需要的方法,而不是需要实现所有未实现的方法。
  • 可以为图片切换添加动画效果,切入时调用ViewFlipper的setInAnimation方法,切出时调用ViewFlipper的setOutAnimation方法,并在XML中自定义动画效果,代码如下:
<!-- 向左滑动时,切入的动画定义 -->
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="200"
        android:fromXDelta="100%p"
        android:toXDelta="0" >
    </translate>

    <alpha
        android:duration="200"
        android:fromAlpha="0.1"
        android:toAlpha="1.0" >
    </alpha>

</set>

<!-- 向左滑动时,切出的动画定义 -->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="200"
        android:fromXDelta="0"
        android:toXDelta="-100%p" />

    <alpha
        android:duration="200"
        android:fromAlpha="1.0"
        android:toAlpha="0.1" >
    </alpha>

</set>

<!-- 向右滑动时,切入的动画定义 -->
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="200"
        android:fromXDelta="-100%p"
        android:toXDelta="0"
        android:zAdjustment="bottom" >
    </translate>

    <alpha
        android:duration="200"
        android:fromAlpha="0.1"
        android:toAlpha="1.0" >
    </alpha>

</set>

<!-- 向右滑动时,切出的动画定义 -->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="200"
        android:fromXDelta="0"
        android:toXDelta="100%p" />

    <alpha
        android:duration="200"
        android:fromAlpha="1.0"
        android:toAlpha="0.1" >
    </alpha>

</set>

需要注意:

  • translate标签用于设置切换起点与终点的相对位移,单位为“%p”;
  • alpha标签用于设置起始位置和终止位置的透明度,范围是0.0-1.0,其中0.0代表完全透明,1.0代表完全不透明。

SimpleOnGestureListener回调方法浅析


在静态子类SimpleOnGestureListener中,一共有10个空实现的回调方法,这些方法会根据不同手势操作而适时回调,开发者也可以为实现某个特定手势而重写特定的方法,而不用将所有方法重写。
在demo中,打印Log,浅析不同手势对应的回调方法:


在屏幕上快速滑动

  • 在屏幕上快速滑动,首先调用onDown,接着是一系列的onScroll,最后是onFling;

单击屏幕

  • 单击屏幕,先后调用onDown,onSingleTapUp,onSingleTapConfirmed;

双指单击屏幕

  • 双指(及双指以上)单击屏幕,仅调用onDown;

在屏幕上慢速滑动

  • 在屏幕上慢速滑动,首先调用onDown,然后是一系列的onScroll,并不调用onFling方法;

用力单击屏幕

  • 用力单击屏幕,依次调用onDown,onShowPress,onSingleTapUp,OnSingleTapConfirmed;

长按屏幕

  • 长按屏幕,依次调用onDown,onShowPress,onLongPress;

双击屏幕

  • 双击屏幕,依次调用onDown,onSingleTapUp,onDoubleTap,onDoubleTapEvent,onDown,onDoubleTapEvent。

至此,除onContextClick未回调以外(该方法涉及到事件分发机制),其余9个方法均在不同手势的操作下被回调,开发者可以在不同手势所回调的方法中编写相应逻辑从而实现手势的捕捉继而触发事件逻辑。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值