android酷狗下拉,Android 仿酷狗滑动控件实现 流畅运行

最近又浏览了一遍github上的开源项目,有感于大神们的强大,所以想搞搞像kugou那样左右滑动的侧滑菜单控件。

打开移动设备的kugou软件,看了下整体效果,就知道了,我们要实现一个左侧主页,右侧菜单,拉动时以缩放式动画进场的控件。

创建项目等一些简单步骤就不说了。让我们来看下主要实现:

自定义一个控件DragLayout,继承自FrameLayout。

public class DragLayout extends FrameLayout {

private boolean isShowShadow = false;

/** * GestureDetectorCompat处理手势识别 * OnGestureListener有下面的几个动作: * 按下(onDown):刚刚手指接触到触摸屏的那一刹那,就是触的那一下。 * 抛掷(onFling): 手指在触摸屏上迅速移动,并松开的动作。 * 长按(onLongPress): 手指按在持续一段时间,并且没有松开。 * 滚动(onScroll): 手指在触摸屏上滑动。 * 按住(onShowPress): 手指按在触摸屏上,它的时间范围在按下起效,在长按之前。 * 抬起(onSingleTapUp):手指离开触摸屏的那一刹那。 */

private GestureDetectorCompat gestureDetector;

private ViewDragHelper dragHelper; // 简化view拖拽操作的帮助类

private DragListener dragListener;

private int range; //菜单关闭时跟原点的距离

private int width;

private int height;

private int mainLeft; //侧菜单距左侧原点位置的距离

private Context context;

// private ImageView iv_shadow;

private RelativeLayout vg_right;

private MyRelativeLayout vg_main;

private Status status = Status.Close;//默认菜单关闭

private boolean isFirstInflate = true;//用来帮助mainLeft第一次获取距离时的

//布尔型,初始化为真,在onSizeChanged()中改变

public DragLayout(Context context) {

this(context, null);

}

public DragLayout(Context context, AttributeSet attrs) {

this(context, attrs, 0);

this.context = context;

}

public DragLayout(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

//初始化手势识别类与view拖曳类

gestureDetector = new GestureDetectorCompat(context,

new YScrollDetector());

dragHelper = ViewDragHelper.create(this, dragHelperCallback);

}

}

首先创建构造器,并初始化GestureDetectorCompat类与ViewDragHelper类。

GestureDetectorCompat类是手势识别类,它对外提供了两个接口:OnGestureListener,OnDoubleTapListener,还有一个内部类SimpleOnGestureListener;SimpleOnGestureListener类是GestureDetector提供给我们的一个更方便的响应不同手势的类,它实现了上述两个接口。

ViewDragHelper类是android简化view拖拽操作的帮助类,作用在一个ViewGroup上,也就是说他不能直接作用到被拖拽的view, 其实这也很好理解,因为view在布局中的位置是父ViewGroup决定的。这个类初始化时,需将ViewDragHelper.Callback参数传进。这个回调也是控件实现侧滑的主要代码,它是连接ViewDragHelper与View之间的桥梁。

private ViewDragHelper.Callback dragHelperCallback = new ViewDragHelper.Callback() {

/** * 处理x方向拖动的,返回值该child现在的位置 */

@Override

public int clampViewPositionHorizontal(View child, int left, int dx) {

if (mainLeft + dx < 0) { //右侧菜单距离原点的位置最小为0,最大为range

return 0;

} else if (mainLeft + dx > range) {

return range;

} else {

return left;

}

}

/** * tryCaptureView(View view, int pointerId) 表示尝试捕获子view,这里一定要返回true, * 返回true表示允许。 */

@Override

public boolean tryCaptureView(View child, int pointerId) {

return true;

}

/** * 获取边界 */

@Override

public int getViewHorizontalDragRange(View child) {

return width;

}

/** * 该方法在手势拖动释放的时候被调用,可以在这里设置子View预期到达的位置, * 如果人为的手势拖动没有到达预期位置,我们可以让子View在人为的拖动结束后,再自动关的滑动到指定位置 */

@Override

public void onViewReleased(View releasedChild, float xvel, float yvel) {

super.onViewReleased(releasedChild, xvel, yvel);

// if (xvel > 0) {

// open();

// } else if (xvel < 0) {

// close();

// } else

if (releasedChild == vg_main && mainLeft < range * 0.3) {

//当拉动主页时,如果mainLeft小于 0.3range,则自动打开

open();

} else if (releasedChild == vg_right && mainLeft < range * 0.7) {

//当拉动菜单页时,如果mainLeft大于 0.7range,则自动打开

open();

} else {//其余都为关闭情况

close();

}

}

private final static String tag = "Draglayout";

/** * 该方法在子view位置发生改变时都会被调用,可以在这个方法中做一些拖动过程中渐变的动画等操作 */

@Override

public void onViewPositionChanged(View changedView, int left, int top,int dx, int dy) {

//根据不同的子view,对mainLeft进行分别赋值

if (changedView == vg_right) { //右侧菜单

mainLeft = left;

Log.d(tag, "vg_main: " + mainLeft + " range: " + range);

} else { //主页

Log.d(tag, "vg_left1: " + mainLeft);

mainLeft = mainLeft + left;

Log.d(tag, "vg_left2: " + mainLeft + " left: " + left);

}

//mainLeft的取值范围

if (mainLeft < 0) {

mainLeft = 0;

} else if (mainLeft > range) {

mainLeft = range;

}

//

// if (isShowShadow) {

// iv_shadow.layout(mainLeft, 0, mainLeft + width, height);

// }

if (changedView == vg_main) {

vg_main.layout(0, 0, width, height);

vg_right.layout(mainLeft, 0, mainLeft + width, height);

}

dispatchDragEvent(mainLeft);

}

};

它主要是实现了以上几种方法,具体方法做何用,可看注释。

在这个方法里,我们需要判断操作的对象,是主界面还是菜单,根据对象的不同,给予mainLeft(侧菜单距左侧原点位置的距离)不同的赋值。在onViewReleased()方法里,判断mainLeft的大小,去打开或者关闭菜单。在onViewPositionChanged()中,对两个界面作拖动过程中的渐变动画。

因为将由ViewDragHelper处理view拖动事件,所以DragLayout的触摸事件也需一并给它处理。

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

return dragHelper.shouldInterceptTouchEvent(ev)

&& gestureDetector.onTouchEvent(ev);

}

@Override

public boolean onTouchEvent(MotionEvent e) {

try {

//必须将layout的触摸事件交由DragHelper类处理!

dragHelper.processTouchEvent(e);

} catch (Exception ex) {

ex.printStackTrace();

}

return false;

}

事件都定义好了,我们还需要实现两个方法:onSizeChanged()和onLayout()

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

width = vg_main.getMeasuredWidth();

height = vg_main.getMeasuredHeight();

range = (int) (width * 0.8f);

//第一次界面初始化时,根据获得的range值对mainLeft进行赋值

if (isFirstInflate) {

mainLeft = range;

isFirstInflate = false;

}

}

@Override

protected void onLayout(boolean changed, int left, int top, int right,

int bottom) {

vg_main.layout(0, 0, width, height);

vg_right.layout(mainLeft, 0, mainLeft + width, height);

}

在onSizeChanged()获取屏幕的高宽,并得到range值(菜单关闭时跟原点的距离)与初始化mainLeft.

其实,主要的实现代码也就是上面这些了,其他的比如渐变动画,以及点击按钮后的拉取与关闭菜单都比较简单,下面有代码下载链接,可以下载下来看看,这是从一个开源项目拷下来做了修改的,变成自己喜欢的风格。所以大神们勿喷哦!

效果图就不上了,不过保证可以使用哦。

最后发现gif好难弄,有大神会的,麻烦给我推荐个工具,可以生成移动设备上的简易gif动画。不胜感激!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值