您的位置:首页 > 移动开发 > Android开发

自定义可拖拽的容器LinearLayout2

2015-11-26 22:22 295 查看
之前的一篇文章“自定义可拖拽的LinearLayout”是监听手势事件,使用layout(),改变整个容器的内容,
但是想了想,改变整个容器的位置不太好,所以今天使用scrollTo,scroBy,通过改变容器里的内容的位置来实现拖拽。
下面附上代码


一.重写onTouchEvent函数,其实就是将上篇的layout(getLeft()+dx,getTop()+dy,getRight()+dx,getBottom()+dy)
改成了scrollBy((int)(-dx)(int)(-dy))

case MotionEvent.ACTION_MOVE: {
// Find the index of the active pointer and fetch its position
final int pointerIndex =
MotionEventCompat.findPointerIndex(ev, mActivePointerId);

final float x = MotionEventCompat.getX(ev, pointerIndex);
final float y = MotionEventCompat.getY(ev, pointerIndex);

// Calculate the distance moved
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;

scrollBy((int) (-dx), (int) (-dy));

invalidate();
mLastTouchX = x;
mLastTouchY = y;

break;
}

二.
但是这样有个不好的地方就是内容可以不限制向某一个方向拖拽直至消失,用户体验不好,
为了更好的体现,实现一个回拉的效果
这里使用增加一个判断 

//获取子视图
LinearLayout view = (LinearLayout) getChildAt(0);
if (view == null) {
return true;
}

//获取子视图中心点
int[] arrs = new int[2];
view.getLocationOnScreen(arrs);
int viewX = arrs[0];
int viewY = arrs[1];
int centerX = ((viewX + view.getWidth()) + viewX) / 2;
int centerY = ((viewY + view.getHeight()) + viewY) / 2;
Log.i("viewX,viewY", "" + viewX + " " + centerY);
Log.i("getWidth(),getHeight", "" + getWidth() + " " + getHeight());
Log.i("xx", "" + centerX + " " + centerY);

//如果子视图的中心超过了屏幕的可见区域则视图回到原来的位置,getScrollX是视图在x轴上平移的距离和
if(centerX<=getLeft()||centerX>getRight()||centerY>getBottom()||centerY<getTop()){
scrollBy(-getScrollX(),-getScrollY());
}

但是由出现了一个问题,scrollBy是瞬间是容器的内容移动到某个位置,为了得到更好的用户体验,使用Scoller达到平滑移动的效果

//如果子视图的中心超过了屏幕的可见区域则视图回到原来的位置,getScrollX是视图在x轴上平移的距离和
if(centerX<=getLeft()||centerX>getRight()||centerY>getBottom()||centerY<getTop()){
mScroller.startScroll(getScrollX(), getScrollY(), -getScrollX(), -getScrollY());

}
重写容器的computeScoll方法

@Override
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
}
}

好了达到了回拉的效果。
但是发现不论往哪个方向过度拖拽都会回到中心,这样也不太好所以添加如下代码,
如果想右过度拖拽,则内容回拉到左边
如果向左过度拖拽,则内容回拉到右边
如果想下过度拖拽,则内容回拉到底部

if (centerY <= getTop() && centerX > getLeft()) {//显示下边
mScroller.startScroll(getScrollX(), getScrollY(), 0, (view.getHeight() - getHeight()) - getScrollY());

invalidate();
return true;
}

if (centerX <= getLeft() || centerY <= getTop()) {//显示右边
mScroller.startScroll(getScrollX(), getScrollY(), (view.getWidth() - getWidth()) - getScrollX(), -getScrollY());
invalidate();
return true;
}
if (centerX >= getRight() || centerY >= getBottom()) {//显示左边
mScroller.startScroll(getScrollX(), getScrollY(), -getScrollX(), -getScrollY());
invalidate();
return true;
}

完整代码如下

package com.beidouapp.ilink.demoapp.widget;

import android.content.Context;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.LinearLayout;
import android.widget.Scroller;

import com.beidouapp.ilink.demoapp.utiles.Util;

/**
* Created by xyb on 2015/11/25.
*/
public class GoogleDragDemo extends LinearLayout {

private float mLastTouchX;
private float mLastTouchY;
private Scroller mScroller;

public GoogleDragDemo(Context context) {
super(context);
}

public GoogleDragDemo(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}

private void init(Context context) {
mScroller = new Scroller(context);
}

// The ‘active pointer’ is the one currently moving our object.
private int INVALID_POINTER_ID = -1000;
private int mActivePointerId = INVALID_POINTER_ID;
@Override public void computeScroll() { super.computeScroll(); if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); invalidate(); } }

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
int action = event.getAction() & MotionEvent.ACTION_MASK;
//为了使手指按在Button等可点击的控件上任可以滑动,需要拦截滑动实践
//并且为了使坐标准确,在此处记录按下的点
switch (action) {
case MotionEvent.ACTION_MOVE:
return true;
case MotionEvent.ACTION_DOWN:
final int pointerIndex = MotionEventCompat.getActionIndex(event);
mActivePointerId = MotionEventCompat.getPointerId(event, pointerIndex);
final float x = MotionEventCompat.getX(event, pointerIndex);
final float y = MotionEventCompat.getY(event, pointerIndex);

// Remember where we started (for dragging)
mLastTouchX = x;
mLastTouchY = y;

// Save the ID of this pointer (for dragging)
mActivePointerId = MotionEventCompat.getPointerId(event, 0);
mActivePointerId = MotionEventCompat.getPointerId(event, 0);
return false;
}
return false;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
// Let the ScaleGestureDetector inspect all events.
// mScaleDetector.onTouchEvent(ev);

final int action = MotionEventCompat.getActionMasked(ev);

switch (action) {
case MotionEvent.ACTION_DOWN: {
break;
}

case MotionEvent.ACTION_MOVE: {
// Find the index of the active pointer and fetch its position
final int pointerIndex =
MotionEventCompat.findPointerIndex(ev, mActivePointerId);

final float x = MotionEventCompat.getX(ev, pointerIndex);
final float y = MotionEventCompat.getY(ev, pointerIndex);

// Calculate the distance moved
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
if(getChildCount()!=1){
Log.e("错误","只能有一个视图");
return true;
}

//获取子视图
LinearLayout view = (LinearLayout) getChildAt(0);

//获取子视图中心点
int[] arrs = new int[2];
view.getLocationOnScreen(arrs);
int viewX = arrs[0];
int viewY = arrs[1];
int centerX = ((viewX + view.getWidth()) + viewX) / 2;
int centerY = ((viewY + view.getHeight()) + viewY) / 2;
Log.i("viewX,viewY", "" + viewX + " " + centerY);
Log.i("getWidth(),getHeight", "" + getWidth() + " " + getHeight());
Log.i("xx", "" + centerX + " " + centerY);

if (centerY <= getTop() && centerX > getLeft()) {//显示下边
mScroller.startScroll(getScrollX(), getScrollY(), 0, (view.getHeight() - getHeight()) - getScrollY());

invalidate();
return true;
}

if (centerX <= getLeft() || centerY <= getTop()) {//显示右边
mScroller.startScroll(getScrollX(), getScrollY(), (view.getWidth() - getWidth) - getScrollX(), -getScrollY());
invalidate();
return true;
}
if (centerX >= getRight() || centerY >= getBottom()) {//显示左边
mScroller.startScroll(getScrollX(), getScrollY(), -getScrollX(), -getScrollY());
invalidate();
return true;
}

scrollBy((int) (-dx), (int) (-dy));

invalidate();
mLastTouchX = x;
mLastTouchY = y;

break;
}

case MotionEvent.ACTION_UP: {
mActivePointerId = INVALID_POINTER_ID;
break;
}

case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}

case MotionEvent.ACTION_POINTER_UP: {

final int pointerIndex = MotionEventCompat.getActionIndex(ev);
final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = MotionEventCompat.getX(ev, newPointerIndex);
mLastTouchY = MotionEventCompat.getY(ev, newPointerIndex);
mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
}
break;
}
}
return true;
}
}


关于scollTo,scrollBy,Scoller.以及android的坐标问题将在下篇讲到
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息