自定义可拖拽的容器LinearLayout2

之前的一篇文章“ 自定义可拖拽的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的坐标问题将在下篇讲到
DragLinearLayout是一个LinearLayout, 他可是其子View在其范围内可拖动、可交换位置。默认情况下,子View是不可拖动的,你需要调用DragLinearLayout.setViewDraggable(child, child)方法让其可拖动。项目地址:https://github.com/justasm/DragLinearLayout 效果图:如何使用和使用LinearLayout一样:                        2. 让子View可拖动默认情况下子View是不可拖动的,你需要调用dragLinearLayout.setViewDraggable()让子View变为可拖动的。DragLinearLayout dragLinearLayout = (DragLinearLayout) findViewById(R.id.container); //让子view可拖动,默认是不能拖动的         for(int i = 1; i < dragLinearLayout.getChildCount(); i ){             View child = dragLinearLayout.getChildAt(i);             dragLinearLayout.setViewDraggable(child, child);          }可以动态添加可拖动子viewfinal View view = View.inflate(context, R.layout.view_layout, null); dragLinearLayout.addDragView(view, view.findViewById(R.id.view_drag_handle));   // ..   dragLinearLayout.removeDragView(view);使用OnViewSwapListener检测子view之间的排序变化事件:dragLinearLayout.setOnViewSwapListener(new DragLinearLayout.OnViewSwapListener() {     @Override     public void onSwap(View firstView, int firstPosition,             View secondView, int secondPosition) {         // update data, etc..     } });当在ScrollView中使用DragLinearLayout的时候,如果你想在拖拽的时候ScrollView也能滚动,需要调用setContainerScrollView(Scroll
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值