1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Android 仿淘宝京东商品详情页阻力翻页效果

Android 仿淘宝京东商品详情页阻力翻页效果

时间:2019-08-02 02:01:21

相关推荐

Android 仿淘宝京东商品详情页阻力翻页效果

原文链接:/p/android-example/diff/46/trunk/%E5%95%86%E5%9F%8E%E8%AF%A6%E6%83%85/src/com

Index: example/shop/DragLayout.java===================================================================--- example/shop/DragLayout.java(revision 0)+++ example/shop/DragLayout.java(revision 46)@@ -0,0 +1,307 @@+package com.example.shop;++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 刘伦+ * @version 1.0+ * @date 1月5日+ */+public class DragLayout extends ViewGroup {+/**+ * 拖动工具类+ */+private final ViewDragHelper mDragHelper;+private GestureDetectorCompat gestureDetectorCompat;+/**+ * 上下两个frameLayout,在Activity中注入fragment+ */+private View frameView1, frameView2;+private int viewHeight;+/**+ * 滑动速度的阈值,超过这个绝对值认为是上下+ */+private static final int VEL_THRESHOLD = 100;+/**+ * 单位是像素,当上下滑动速度不够时,通过这个阈值来判定是应该粘到顶部还是底部+ */+private static final int DISTANCE_THRESHOLD = 100;++/**+ * 手指按下,frameView1的gettop+ */+private int downTop1;++/**+ * 手指松开是否加载一下一页的notifier+ */+private ShowNextPageNotifier nextPageNotifier;++public DragLayout(Context context, AttributeSet attrs) {+this(context, attrs, 0);+}++public DragLayout(Context context) {+this(context, null);+}++public DragLayout(Context context, AttributeSet attrs, int defStyle) {+super(context, attrs, defStyle);+mDragHelper = ViewDragHelper+.create(this, 10f, new DragHelperCallback());+mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_BOTTOM);+gestureDetectorCompat = new GestureDetectorCompat(context,+new YScrollDetector());+}++@Override+protected void onFinishInflate() {+// 初始化两个view+frameView1 = getChildAt(0);+frameView2 = getChildAt(1);+}++@Override+public void computeScroll() {+if (mDragHelper.continueSettling(true)) {+ViewCompat.postInvalidateOnAnimation(this);+}+}+@Override+public boolean onInterceptTouchEvent(MotionEvent ev) {+if(frameView1.getBottom()>0&&frameView1.getTop()<0){+//view在顶部或者底部,正在动画中的时候,不处理touch事件+return false;+}+boolean yScroll=gestureDetectorCompat.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;+}+@Override+public boolean onTouchEvent(MotionEvent event) {+// 统一交给mDragHelper处理 由DragHelperCallback实现拖动效果+mDragHelper.processTouchEvent(event);+return true;+}++@Override+protected void onLayout(boolean changed, int l, int t, int r, int b) {+if (frameView1.getTop() == 0) {+frameView1.layout(l, 0, r, b - t);+frameView2.layout(l, 0, r, b - t);++viewHeight = frameView1.getMeasuredHeight();+frameView2.offsetTopAndBottom(viewHeight);+} else {+// 如果已经被初始化,这次onLayout只需将之前的状态存入即可+frameView1+.layout(l, frameView1.getTop(), r, frameView1.getBottom());+frameView2+.layout(l, frameView2.getTop(), r, frameView2.getBottom());+}+}++@SuppressLint("NewApi")+@Override+protected 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 nextPageNotifier) {+this.nextPageNotifier = nextPageNotifier;+}++/**+ * 手势监听+ * + * @author 刘伦+ * @version 1.0+ * @date 1月5日+ */+private class YScrollDetector extends SimpleOnGestureListener {+@Override+public boolean onScroll(MotionEvent e1, MotionEvent e2,+float distanceX, float distanceY) {+// 垂直滚动时dy>dx,才被认定是上下拖动+return Math.abs(distanceY) > Math.abs(distanceX);+}+}++/**+ * 滑动时view位置改变协调处理+ * + * @param viewIndex+ * 滑动view的index(1或2)+ * @param posTop+ * 滑动View的top位置+ */+private void onViewPosChanged(int viewIndex, int top) {+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);+}++}++/**+ * 拖拽效果主要逻辑+ * + * @author 刘伦+ * @version 1.0+ * @date 1月5日+ */+private class DragHelperCallback extends ViewDragHelper.Callback {++@Override+public 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);+}++/**+ * 返回值可以决定一个parentview中哪个子view可以拖动+ */+@Override+public boolean tryCaptureView(View arg0, int arg1) {+// TODO Auto-generated method stub+return true;+}++@Override+public int getViewVerticalDragRange(View child) {+return 1;+}++/**+ * 滑动松开后+ */+@Override+public void onViewReleased(View releasedChild, float xvel, float yvel) {+animTopOrBottom(releasedChild, yvel);+}++@Override+public int clampViewPositionVertical(View child, int top, int dy) {+int finalTop = top;+// 第一个view被拖动+if (child == frameView1) {+if (top > 0) {+// 不让第一个view网上拖,因为顶部会白板+finalTop = 0;+}+} else if (child == frameView2) {// 第二个view被拖动+if (top < 0) {+// 不让第二个view往上拖动,因为底部会白板+finalTop = 0;+}+}+// finalTop代表的是理论上应该拖动到的位置。此处计算拖动的距离除以一个参数(3),+// 是让滑动的速度变慢。数值越大,滑动的越慢+return child.getTop() + (finalTop - child.getTop()) / 3;+}+}++/**+ * 滑动松开后,需要向上或者乡下粘到特定的位置+ * + * @param releasedChild+ * @param yvel+ * @author LiuLun+ * @Time 1月7日上午10:50:08+ */+public 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 (nextPageNotifier != null) {+nextPageNotifier.onDragNext();+}+}+} else {+// 拖动第二个view松手+if (yvel > VEL_THRESHOLD+|| (downTop1 == -viewHeight && releasedChild.getTop() > DISTANCE_THRESHOLD)) {+// 保持原地不懂+finalTop = viewHeight;+}+}++if (mDragHelper.smoothSlideViewTo(releasedChild, 0, finalTop)) {+ViewCompat.postInvalidateOnAnimation(this);+}++}++public interface ShowNextPageNotifier {+public void onDragNext();+}++}Index: example/shop/VerticalFragment1.java===================================================================--- example/shop/VerticalFragment1.java(revision 0)+++ example/shop/VerticalFragment1.java(revision 46)@@ -0,0 +1,22 @@+package com.example.shop;++import android.graphics.Paint;+import android.os.Bundle;+import android.support.v4.app.Fragment;+import android.view.LayoutInflater;+import android.view.View;+import android.view.ViewGroup;+import android.widget.TextView;++public class VerticalFragment1 extends Fragment {++@Override+public View onCreateView(LayoutInflater inflater, ViewGroup container,+Bundle savedInstanceState) {+View rootView = inflater.inflate(R.layout.vertical_fragment1, null);+TextView oldTextView = (TextView) rootView+.findViewById(R.id.old_textview);+oldTextView.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);+return rootView;+}+}Index: example/shop/VerticalFragment2.java===================================================================--- example/shop/VerticalFragment2.java(revision 0)+++ example/shop/VerticalFragment2.java(revision 46)@@ -0,0 +1,65 @@+package com.example.shop;++import android.os.Bundle;+import android.support.v4.app.Fragment;+import android.view.LayoutInflater;+import android.view.View;+import android.view.ViewGroup;+import android.widget.BaseAdapter;+import android.widget.ListAdapter;+import android.widget.ListView;++public class VerticalFragment2 extends Fragment {++@Override+public View onCreateView(LayoutInflater inflater, ViewGroup container,+Bundle savedInstanceState) {+View rootView = inflater.inflate(R.layout.vertical_fragment2, null);+initView(rootView);+return rootView;+}++/**+ * 初始化ListView+ * + * @param rootView+ * 根View+ */+private void initView(View rootView) {+ListView listview = (ListView) rootView+.findViewById(R.id.fragment2_listview);+ListAdapter adapter = new BaseAdapter() {+private LayoutInflater inflater;++@Override+public View getView(int position, View convertView, ViewGroup parent) {+if (inflater == null) {+inflater = LayoutInflater.from(getActivity());+}++if (null == convertView) {+convertView = inflater.inflate(+R.layout.fragment2_list_item, null);+}+return convertView;+}++@Override+public long getItemId(int position) {+return position;+}++@Override+public Object getItem(int position) {+return position;+}++@Override+public int getCount() {+return 100;+}+};++listview.setAdapter(adapter);+}+}Index: example/shop/VerticalFragment3.java===================================================================--- example/shop/VerticalFragment3.java(revision 0)+++ example/shop/VerticalFragment3.java(revision 46)@@ -0,0 +1,31 @@+package com.example.shop;++import android.os.Bundle;+import android.support.v4.app.Fragment;+import android.view.LayoutInflater;+import android.view.View;+import android.view.ViewGroup;++public class VerticalFragment3 extends Fragment {++private View progressBar;+private CustWebView webview;+private boolean hasInited = false;++@Override+public View onCreateView(LayoutInflater inflater, ViewGroup container,+Bundle savedInstanceState) {+View rootView = inflater.inflate(R.layout.vertical_fragment3, null);+webview = (CustWebView) rootView.findViewById(R.id.fragment3_webview);+progressBar = rootView.findViewById(R.id.progressbar);+return rootView;+}++public void initView() {+if (null != webview && !hasInited) {+hasInited = true;+progressBar.setVisibility(View.GONE);+webview.loadUrl("/tuan/");+}+}+}Index: example/shop/MainActivity.java===================================================================--- example/shop/MainActivity.java(revision 0)+++ example/shop/MainActivity.java(revision 46)@@ -0,0 +1,44 @@+package com.example.shop;++import android.os.Bundle;+import android.support.v4.app.FragmentActivity;+import android.view.Window;++import com.example.shop.DragLayout.ShowNextPageNotifier;++public class MainActivity extends FragmentActivity {++private VerticalFragment1 fragment1;+private VerticalFragment3 fragment3;+private DragLayout draglayout;++@Override+protected void onCreate(Bundle savedInstanceState) {+super.onCreate(savedInstanceState);+requestWindowFeature(Window.FEATURE_NO_TITLE);+setContentView(R.layout.activity_main);+initView();+}++/**+ * 初始化View+ */+private void initView() {+fragment1 = new VerticalFragment1();+fragment3 = new VerticalFragment3();++getSupportFragmentManager().beginTransaction()+.add(R.id.first, fragment1).add(R.id.second, fragment3)+.commit();++ShowNextPageNotifier nextIntf = new ShowNextPageNotifier() {+@Override+public void onDragNext() {+fragment3.initView();+}+};+draglayout = (DragLayout) findViewById(R.id.draglayout);+draglayout.setNextPageListener(nextIntf);+}++}Index: example/shop/CustListView.java===================================================================--- example/shop/CustListView.java(revision 0)+++ example/shop/CustListView.java(revision 46)@@ -0,0 +1,87 @@+package com.example.shop;++import android.content.Context;+import android.util.AttributeSet;+import android.view.MotionEvent;+import android.view.View;+import android.widget.ListView;++public class CustListView extends ListView {+/**+ * 如果是true,则允许拖动至底部的下一页+ */+private boolean allowDragTop = true;+/**+ * 当前点击事件相对于屏幕的y轴+ */+private float downY = 0;+/**+ * 是否需要承包touch事件,needConsumeTouch一旦被定型, 则不会更改+ */+private boolean needConsumeTouch = true;++public CustListView(Context context, AttributeSet attrs) {+this(context, attrs, 0);+}++public CustListView(Context context) {+this(context, null);+}++public CustListView(Context context, AttributeSet attrs, int defStyle) {+super(context, attrs, defStyle);+}++@Override+public boolean dispatchTouchEvent(MotionEvent ev) {+if (ev.getAction() == MotionEvent.ACTION_DOWN) {+downY = ev.getRawX();+// 默认情况下,listview内部滚动优先,默认情况下由该listview去小费touch事件+needConsumeTouch = true;+allowDragTop = isAtTop();+} else if (ev.getAction() == MotionEvent.ACTION_MOVE) {+if (!needConsumeTouch) {+// 在最顶端且向上拉了,则这个touch事件交由父类去处理+getParent().requestDisallowInterceptTouchEvent(false);+return false;+} else if (allowDragTop) {+// needConsumeTouch尚未被定型,此处给起定性+// 允许拖动到底部的下一页,而且有向上拖动了,就将touch事件交由父view+if (ev.getRawY() - downY > 2) {+// flag设置,由父类去小费+needConsumeTouch = false;+getParent().requestDisallowInterceptTouchEvent(false);+return false;+}+}+}+// 通知父view是否要处理touch事件+getParent().requestDisallowInterceptTouchEvent(needConsumeTouch);+return super.dispatchTouchEvent(ev);+}++/**+ * 是否在顶部+ * + * @author LiuLun+ * @Time 1月5日下午3:11:13+ */+private boolean isAtTop() {+boolean resultValue = false;+int childNum = getChildCount();++if (childNum == 0) {+// 没child,在顶部+resultValue = true;+} else {+if (getFirstVisiblePosition() == 0) {+// 根据第一个childView来判定是否在顶部+View firstView = getChildAt(0);+if (Math.abs(firstView.getTop() - getTop()) < 2) {+resultValue = true;+}+}+}+return resultValue;+}+}Index: example/shop/CustWebView.java===================================================================--- example/shop/CustWebView.java(revision 0)+++ example/shop/CustWebView.java(revision 46)@@ -0,0 +1,57 @@+package com.example.shop;++import android.content.Context;+import android.util.AttributeSet;+import android.view.MotionEvent;+import android.webkit.WebView;++public class CustWebView extends WebView {+private boolean allowDragTop = true;+private float downY = 0;+private boolean needConsumeTouch = true;++public CustWebView(Context context, AttributeSet attrs) {+this(context, attrs, 0);+}++public CustWebView(Context context) {+this(context, null);+}++public CustWebView(Context context, AttributeSet attrs, int defStyle) {+super(context, attrs, defStyle);+}++@Override+public boolean dispatchTouchEvent(MotionEvent ev) {+if(ev.getAction()==MotionEvent.ACTION_DOWN){+downY=ev.getRawY();+needConsumeTouch=true;+allowDragTop=isAtTop();+}else if(ev.getAction()==MotionEvent.ACTION_MOVE){+if(!needConsumeTouch){+getParent().requestDisallowInterceptTouchEvent(false);+return false;+}else if(allowDragTop){+if(ev.getRawY()-downY>2){+needConsumeTouch=false;+getParent().requestDisallowInterceptTouchEvent(false);+return false;+}+}+}+getParent().requestDisallowInterceptTouchEvent(needConsumeTouch);+return super.dispatchTouchEvent(ev);+}++/**+ * 是否在listview顶部+ * + * @return+ * @author LiuLun+ * @Time 1月5日下午4:07:36+ */+private boolean isAtTop() {+return getScrollY() == 0;+}+}Index: example/shop/CustScrollView.java===================================================================--- example/shop/CustScrollView.java(revision 0)+++ example/shop/CustScrollView.java(revision 46)@@ -0,0 +1,72 @@+package com.example.shop;++import android.content.Context;+import android.util.AttributeSet;+import android.view.MotionEvent;+import android.widget.ScrollView;++public class CustScrollView extends ScrollView{+/**+ * 如果是ture,则允许拖动至底部的下一页+ */+private boolean allowDragBottom=true;+private float downY=0;+/**+ * 是否需要承包touch事件,needConsumeTouch一旦被定型,则不会更改+ */+private boolean needConsumeTouch=true;+/**+ * 最大滑动距离+ */+private int maxScroll=-1;+public CustScrollView(Context context, AttributeSet attrs) {+this(context, attrs,0);+}++public CustScrollView(Context context) {+this(context,null);+}+public CustScrollView(Context context, AttributeSet attrs, int defStyle) {+super(context, attrs, defStyle);+}++@Override+public boolean dispatchTouchEvent(MotionEvent ev) {+if(ev.getAction()==MotionEvent.ACTION_DOWN){+downY=ev.getRawY();+needConsumeTouch=true;+if(maxScroll>0&&getScrollY()+getMeasuredHeight()>=maxScroll-2){+//允许向上拖动底部的下一页+allowDragBottom=true;+}else{+//不允许向上拖动底部的下一页+allowDragBottom=false;+}+}else if(ev.getAction()==MotionEvent.ACTION_MOVE){+if(!needConsumeTouch){+//在最顶端且向上拉,则这个touch事件交由父类去处理+getParent().requestDisallowInterceptTouchEvent(false);+return false;+}else if(allowDragBottom){+//needConsumeTouch尚未被定型,此处给其定型+//允许拖动到底部的下一页,而且又被向上拖动了,将touch事件交由父view+if(downY-ev.getRawY()>2){+//flag设置,由父类去小费+needConsumeTouch=false;+getParent().requestDisallowInterceptTouchEvent(false);+return false;+}+}+}+//通知父view是否要处理touch事件+getParent().requestDisallowInterceptTouchEvent(needConsumeTouch);+return super.dispatchTouchEvent(ev);+}+@Override+protected void onScrollChanged(int l, int t, int oldl, int oldt) {+if(maxScroll<0){+maxScroll=computeVerticalScrollRange();+}+super.onScrollChanged(l, t, oldl, oldt);+}+}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。