手势识别和处理触摸事件是开发用户交互的重要事项,处理标准事件例如点击,长按,按键等等是基础的其他教程介绍的,这项教程是关注于处理一些专业的手势例如:
- 向某个方向滑动
- 双击放大
- 手捏放大或缩小
- 滑动列表的效果
所有手势的核心是onTouchListener
和onTouch
方法后者有对动作数据MotionEvent
有访问权限.每个view都有onTouchListener
可以指定:
myView.setOnTouchListener(new OnTouchListener()) {
@Overdide
public boolean onTouch(View v, MotionEvent event) {
//解读动作数据,处理相关事件
}
});
每个onTouch
都对动作事件具有访问权限,动作事件包含了一个动作代码和一组轴值。动作代码描述了发生的状态的改变,例如指针的上下移动。轴值形容了位置和一些其他的属性:
- getAction
返回一个整数常量MotionEvent.ACTION_DOWN , MotionEvent.ACTION_MOVE, MotionEvent.ACTION_UP
-getX()
返回触摸事件的x坐标
- getY()
返回点击事件的y坐标
记住每个触摸事件可以在整个受影响的view层传播,每个包含这个view的布局都可能会对事件进行反馈。
记住getAction
正常的包含的信息既包括动作也包括指针索引。在单触摸事件中,只有一个指针(设置为0)不需要位图掩码,在多点触摸情况下需要其他的方法确定触摸事件:
- getActionMasked()
没有指针索引的情况下获取动作事件
- getActionIndex()
获取使用的指针索引
与其他指针相联系的事件一般以MotionEvent.ACTION_POINTER
开始,例如MotionEvent.ACTION_POINTER_DOWN
和MotionEvent.ACTION_POINTER_UP
使用getPointerCount()
可以知道在触摸序列中多少指针被激活了。
在onTouch
事件中我们可以使用GestureDetector
来理解基于一系列动作的手势。
使用OnDoubleTapListener,:
myView.setOnTouchListener(new OnDoubleTapListener(this)) {
@Override
public void onDoubleTap(MotionEvent e) {
Toast.makeText。。。
}
});
使用onSwipeTouchListener
myView.setOnTouchListener(new OnSwipeTouchListener(this){
@Override
public void onSwipeDown() {
Toast.makeText(MainActivity.this, "Down", Toast.LENGTH_SHORT).show();
}
@Override
public void onSwipeLeft() {
Toast.makeText(MainActivity.this, "Left", Toast.LENGTH_SHORT).show();
}
@Override
public void onSwipeUp() {
Toast.makeText(MainActivity.this, "Up", Toast.LENGTH_SHORT).show();
}
@Override
public void onSwipeRight() {
Toast.makeText(MainActivity.this, "Right", Toast.LENGTH_SHORT).show();
}
});
我们可以让ListView的每一项来感应滑动手势,采用第三方库android-swipelistview。待续。。。
我们可以使用ScaleGestureDetector类
public class ScaleableTextView extends TextView
implements OnTouchListener, OnScaleGestureListener {
ScaleGestureDetector mScaleDetector =
new ScaleGestureDetector(getContext(), this);
public ScaleableTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
// Code for scale here
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
// Code for scale begin here
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
// Code for scale end here
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (mScaleDetector.onTouchEvent(event))
return true;
return super.onTouchEvent(event);
}
}
最常见的是对ImageView进行缩放操作,需要使用PhotoView
第三方库
XML文件
.co.senab.photoview.PhotoView
android:id="@+id/iv_photo"
android:layout_width="match_parent"
android:layout_height="match_parent" />
java:
// Any implementation of ImageView can be used!
mImageView = (ImageView) findViewById(R.id.iv_photo);
// Set the image bitmap
mImageView.setImageDrawable(someBitmap);
// Setup view attacher
PhotoViewAttacher mAttacher = new PhotoViewAttacher(mImageView
对于RecyclerView我们可以使用addOnScrollListener对于ListView我们可以使用setOnScollListener
首先我们要可拖动的view上添加一个onTouch
处理器,开始拖动的时候可以创建一个DragShadow
,我们需要DragShadowBuilder
当拖动开始时
draggableView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN ) {
//构建拖动阴影
DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view);
//开始阴影拖动
view.startDrag(null, shadowBuilder, view, 0);
//隐藏view
view.setVisibility(View.INVISIBLE);
return true;
}
} else {
return false;
}
})
想要添加拖放事件的话我们需要创造一个DragListener
连接到一个拖动的区域。
// This listener is attached to the view that should be a drop target
viewDropZone.setOnDragListener(new OnDragListener() {
// Drawable for when the draggable enters the drop target
Drawable enteredZoneBackground = getResources().getDrawable(R.drawable.shape_border_green);
// Drawable for the default background of the drop target
Drawable defaultBackground = getResources().getDrawable(R.drawable.shape_border_red);
@Override
public boolean onDrag(View v, DragEvent event) {
// Get the dragged view being dropped over a target view
final View draggedView = (View) event.getLocalState();
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
// Signals the start of a drag and drop operation.
// Code for that event here
break;
case DragEvent.ACTION_DRAG_ENTERED:
// Signals to a View that the drag point has
// entered the bounding box of the View.
v.setBackground(enteredZoneBackground);
break;
case DragEvent.ACTION_DRAG_EXITED:
// Signals that the user has moved the drag shadow
// outside the bounding box of the View.
v.setBackground(defaultBackground);
break;
case DragEvent.ACTION_DROP:
// Signals to a View that the user has released the drag shadow,
// and the drag point is within the bounding box of the View.
// Get View dragged item is being dropped on
View dropTarget = v;
// Make desired changes to the drop target below
dropTarget.setTag("dropped");
// Get owner of the dragged view and remove the view (if needed)
ViewGroup owner = (ViewGroup) draggedView.getParent();
owner.removeView(draggedView);
break;
case DragEvent.ACTION_DRAG_ENDED:
// Signals to a View that the drag and drop operation has concluded.
// If event result is set, this means the dragged view was dropped in target
if (event.getResult()) { // drop succeeded
v.setBackground(enteredZoneBackground);
} else { // drop did not occur
// restore the view as visible
draggedView.post(new Runnable() {
@Override
public void run() {
draggedView.setVisibility(View.VISIBLE);
}
});
// restore drop zone default background
v.setBackground(defaultBackground);
}
default:
break;
}
return true;
}
});
首先我们需要一个shakeListenerhttps://gist.github.com/nesquena/5d1922a5a50fcfb4436a
然后使用方法:
public class MainActivity extends Activity
implements ShakeListener.Callback {
@Override
public void shakingStarted() {
// Code on started here
}
@Override
public void shakingStopped() {
// Code on stopped here
}
}