向上拖动时,可以惯性滑动显示到下一页的控件DragLayout

来源:互联网 发布:单片机LED接线 编辑:程序博客网 时间:2024/04/25 23:58
仿照淘宝和聚美优品,在商品详情页,向上拖动时,可以加载下一页。使用ViewDragHelper,滑动比较流畅。 scrollView滑动到底部的时候,再行向上拖动时,添加了一些阻力。

只支持两页!




import android.annotation.SuppressLint;import android.content.Context;import android.support.v4.view.GestureDetectorCompat;import android.support.v4.view.ViewCompat;import android.support.v4.widget.ViewDragHelper;import android.util.AttributeSet;import android.view.GestureDetector.SimpleOnGestureListener;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;/** * 这是一个viewGroup容器,实现上下两个frameLayout拖动切换 *  * @author sistone.Zhang */@SuppressLint("NewApi")public class DragLayout extends ViewGroup {/* 拖拽工具类 */private final ViewDragHelper mDragHelper;private GestureDetectorCompat gestureDetector;/* 上下两个frameLayout,在Activity中注入fragment */private View frameView1, frameView2;private int viewHeight;private static final int VEL_THRESHOLD = 100; // 滑动速度的阈值,超过这个绝对值认为是上下private static final int DISTANCE_THRESHOLD = 100; // 单位是像素,当上下滑动速度不够时,通过这个阈值来判定是应该粘到顶部还是底部private int downTop1; // 手指按下的时候,frameView1的getTop值private ShowNextPageNotifier nextPageListener; // 手指松开是否加载下一页的notifierpublic DragLayout(Context context) {this(context, null);}public DragLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public DragLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);mDragHelper = ViewDragHelper.create(this, 10f, new DragHelperCallback());mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_BOTTOM);gestureDetector = new GestureDetectorCompat(context,new YScrollDetector());}@Overrideprotected void onFinishInflate() {// 跟findviewbyId一样,初始化上下两个viewframeView1 = getChildAt(0);frameView2 = getChildAt(1);}class YScrollDetector extends SimpleOnGestureListener {@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float dx,float dy) {// 垂直滑动时dy>dx,才被认定是上下拖动return Math.abs(dy) > Math.abs(dx);}}@Overridepublic void computeScroll() {if (mDragHelper.continueSettling(true)) {ViewCompat.postInvalidateOnAnimation(this);}}/** * 这是拖拽效果的主要逻辑 */private class DragHelperCallback extends ViewDragHelper.Callback {@Overridepublic void onViewPositionChanged(View changedView, int left, int top,int dx, int dy) {int childIndex = 1;if (changedView == frameView2) {childIndex = 2;}// 一个view位置改变,另一个view的位置要跟进onViewPosChanged(childIndex, top);}@Overridepublic boolean tryCaptureView(View child, int pointerId) {// 两个子View都需要跟踪,返回truereturn true;}@Overridepublic int getViewVerticalDragRange(View child) {// 这个用来控制拖拽过程中松手后,自动滑行的速度,暂时给一个随意的数值return 1;}@Overridepublic void onViewReleased(View releasedChild, float xvel, float yvel) {// 滑动松开后,需要向上或者乡下粘到特定的位置animTopOrBottom(releasedChild, yvel);}@Overridepublic int clampViewPositionVertical(View child, int top, int dy) {int finalTop = top;if (child == frameView1) {// 拖动的时第一个viewif (top > 0) {// 不让第一个view往下拖,因为顶部会白板finalTop = 0;}} else if (child == frameView2) {// 拖动的时第二个viewif (top < 0) {// 不让第二个view网上拖,因为底部会白板finalTop = 0;}}// finalTop代表的是理论上应该拖动到的位置。此处计算拖动的距离除以一个参数(3),是让滑动的速度变慢。数值越大,滑动的越慢return child.getTop() + (finalTop - child.getTop()) / 3;}}/** * 滑动时view位置改变协调处理 *  * @param viewIndex *            滑动view的index(1或2) * @param posTop *            滑动View的top位置 */private void onViewPosChanged(int viewIndex, int posTop) {if (viewIndex == 1) {int offsetTopBottom = viewHeight + frameView1.getTop()- frameView2.getTop();frameView2.offsetTopAndBottom(offsetTopBottom);} else if (viewIndex == 2) {int offsetTopBottom = frameView2.getTop() - viewHeight- frameView1.getTop();frameView1.offsetTopAndBottom(offsetTopBottom);}// 有的时候会默认白板,这个很恶心。后面有时间再优化invalidate();}private void animTopOrBottom(View releasedChild, float yvel) {int finalTop = 0; // 默认是粘到最顶端if (releasedChild == frameView1) {// 拖动第一个view松手if (yvel < -VEL_THRESHOLD|| (downTop1 == 0 && frameView1.getTop() < -DISTANCE_THRESHOLD)) {// 向上的速度足够大,就滑动到顶端// 向上滑动的距离超过某个阈值,就滑动到顶端finalTop = -viewHeight;// 下一页可以初始化了if (null != nextPageListener) {nextPageListener.onDragNext();}}} else {// 拖动第二个view松手if (yvel > VEL_THRESHOLD|| (downTop1 == -viewHeight && releasedChild.getTop() > DISTANCE_THRESHOLD)) {// 保持原地不动finalTop = viewHeight;}}if (mDragHelper.smoothSlideViewTo(releasedChild, 0, finalTop)) {ViewCompat.postInvalidateOnAnimation(this);}}/* touch事件的拦截与处理都交给mDraghelper来处理 */@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {if (frameView1.getBottom() > 0 && frameView1.getTop() < 0) {// view粘到顶部或底部,正在动画中的时候,不处理touch事件return false;}boolean yScroll = gestureDetector.onTouchEvent(ev);boolean shouldIntercept = mDragHelper.shouldInterceptTouchEvent(ev);int action = ev.getActionMasked();if (action == MotionEvent.ACTION_DOWN) {// action_down时就让mDragHelper开始工作,否则有时候导致异常 他大爷的mDragHelper.processTouchEvent(ev);downTop1 = frameView1.getTop();}return shouldIntercept && yScroll;}@Overridepublic boolean onTouchEvent(MotionEvent e) {// 统一交给mDragHelper处理,由DragHelperCallback实现拖动效果mDragHelper.processTouchEvent(e); // 该行代码可能会抛异常,正式发布时请将这行代码加上try catchreturn true;}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// 只在初始化的时候调用// 一些参数作为全局变量保存起来frameView1.layout(l, 0, r, b - t);frameView2.layout(l, 0, r, b - t);viewHeight = frameView1.getMeasuredHeight();frameView2.offsetTopAndBottom(viewHeight);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {measureChildren(widthMeasureSpec, heightMeasureSpec);int maxWidth = MeasureSpec.getSize(widthMeasureSpec);int maxHeight = MeasureSpec.getSize(heightMeasureSpec);setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, 0),resolveSizeAndState(maxHeight, heightMeasureSpec, 0));}/** * 这是View的方法,该方法不支持android低版本(2.2、2.3)的操作系统,所以手动复制过来以免强制退出 */public static int resolveSizeAndState(int size, int measureSpec,int childMeasuredState) {int result = size;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);switch (specMode) {case MeasureSpec.UNSPECIFIED:result = size;break;case MeasureSpec.AT_MOST:if (specSize < size) {result = specSize | MEASURED_STATE_TOO_SMALL;} else {result = size;}break;case MeasureSpec.EXACTLY:result = specSize;break;}return result | (childMeasuredState & MEASURED_STATE_MASK);}public void setNextPageListener(ShowNextPageNotifier nextPageListener) {this.nextPageListener = nextPageListener;}public interface ShowNextPageNotifier {public void onDragNext();}}


用法:
private void initView() {fragment1 = new VerticalFragment1();fragment2 = new VerticalFragment2();//fragment3 = new VerticalFragment3();getSupportFragmentManager().beginTransaction().add(R.id.first, fragment1).add(R.id.second, fragment2)//.add(R.id.second, fragment3)//只支持两页.commit();ShowNextPageNotifier nextIntf = new ShowNextPageNotifier() {@Overridepublic void onDragNext() {//fragment3.initView();}};draglayout = (DragLayout) findViewById(R.id.draglayout);draglayout.setNextPageListener(nextIntf);}


布局:
<com.stone.verticalslide.DragLayout        android:id="@+id/draglayout"        android:layout_width="match_parent"        android:layout_height="match_parent"        >        <FrameLayout            android:id="@+id/first"            android:layout_width="fill_parent"            android:layout_height="fill_parent" />        <FrameLayout            android:id="@+id/second"            android:layout_width="fill_parent"            android:layout_height="fill_parent" />    </com.stone.verticalslide.DragLayout>


////////////////////////////////////////////////////////////////////
仿淘宝商品浏览界面, 向上拉查看详情
http://blog.csdn.net/mr_wanggang/article/details/46356421


这是一个多功能的扩展GridView 可展开,可拖动,可排序,可删除。 固定更多按钮。 展开合并支持动画。 支持箭头图标移动。 数据的处理和显示使用Bean。 来自于500彩票Andorid客户端首页功能。
http://www.jcodecraeer.com/a/opensource/2015/0827/3376.html

自定义商品详情页
http://blog.csdn.net/qq_22271479/article/details/68490868
  • 大小: 1.1 MB
  • android-vertical-slide-view-master.zip (2.6 MB)
  • 下载次数: 11
  • 查看图片附件
0 1
原创粉丝点击