国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android 仿淘寶、京東商品詳情頁向上拖動查看圖文詳情控件DEMO詳解

2019-12-12 05:25:31
字體:
來源:轉載
供稿:網友

一、淘寶商品詳情頁效果

我們的效果

二、實現思路

     使用兩個scrollView,兩個scrollView 豎直排列,通過自定義viewGroup來控制兩個scrollView的豎直排列,以及滑動事件的處理。如下圖

三、具體實現

1、繼承viewGroup自定義布局View 重寫onMeasure()和onLayout方法,在onLayout方法中完成對兩個子ScrollView的豎直排列布局,代碼如下:
布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  xmlns:tools="http://schemas.android.com/tools"  android:layout_width="match_parent"  android:layout_height="match_parent"  tools:context="com.baoyunlong.view.pulluptoloadmore.MainActivity">  <com.baoyunlong.view.pulluptoloadmore.PullUpToLoadMore   android:layout_width="match_parent"   android:layout_height="match_parent"   android:orientation="vertical">   <com.baoyunlong.view.pulluptoloadmore.MyScrollView    android:layout_width="match_parent"    android:layout_height="match_parent"    android:fillViewport="true">    <LinearLayout     android:layout_width="match_parent"     android:layout_height="match_parent"     android:orientation="vertical">     <ImageView      android:scaleType="fitXY"      android:src="@drawable/a1"      android:layout_width="match_parent"      android:layout_height="180dp" />     <TextView      android:text="這里是標題"      android:textSize="18dp"      android:layout_marginRight="10dp"      android:layout_marginLeft="10dp"      android:layout_marginTop="10dp"      android:layout_width="match_parent"      android:layout_height="wrap_content" />     <TextView      android:layout_marginTop="10dp"      android:text="子標題"      android:layout_marginLeft="10dp"      android:layout_marginRight="10dp"      android:textSize="18dp"      android:layout_width="match_parent"      android:layout_height="wrap_content" />     ..............     <LinearLayout      android:layout_height="0dp"      android:layout_weight="1"      android:gravity="bottom"      android:layout_width="match_parent">      <TextView       android:layout_width="match_parent"       android:layout_height="wrap_content"       android:height="50dp"       android:background="#b11"       android:gravity="center"       android:text="繼續(xù)拖動查看圖文詳情"       android:textColor="#000" />     </LinearLayout>    </LinearLayout>   </com.baoyunlong.view.pulluptoloadmore.MyScrollView>   <com.baoyunlong.view.pulluptoloadmore.MyScrollView    android:layout_width="match_parent"    android:layout_height="match_parent"    android:fillViewport="true">    <LinearLayout     android:layout_width="match_parent"     android:layout_height="match_parent"     android:gravity="center"     android:orientation="vertical">     <ImageView      android:layout_width="wrap_content"      android:layout_height="wrap_content"      android:src="@drawable/a1" />     <ImageView      android:layout_width="wrap_content"      android:layout_height="wrap_content"      android:src="@drawable/a3" />     .........    </LinearLayout> </com.baoyunlong.view.pulluptoloadmore.MyScrollView> </com.baoyunlong.view.pulluptoloadmore.PullUpToLoadMore> </RelativeLayout> 

代碼:

public class PullUpToLoadMore extends ViewGroup {  public PullUpToLoadMore(Context context) {   super(context);  }  public PullUpToLoadMore(Context context, AttributeSet attrs) {   super(context, attrs);  }  public PullUpToLoadMore(Context context, AttributeSet attrs, int defStyleAttr) {   super(context, attrs, defStyleAttr);  }  @Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {   super.onMeasure(widthMeasureSpec, heightMeasureSpec);   measureChildren(widthMeasureSpec, heightMeasureSpec);  }  @Override  protected void onLayout(boolean changed, int l, int t, int r, int b) {   int childCount = getChildCount();   int childTop = t;   for (int i = 0; i < childCount; i++) {    View child = getChildAt(i);    child.layout(l, childTop, r, childTop + child.getMeasuredHeight());    childTop += child.getMeasuredHeight();   }  } } 

2、處理滑動事件   

   規(guī)則如下 :     

   (1)、當處于第一屏時 第一個ScrollView已經滑動到底部并且滑動方向是往上滑動,這個時候滑動事件應該交給父view處理也就是攔截事件讓onInterceptTouchEvent返回true.然后父view通過scrollBy()方法滾動,顯示出第二個scrollView。   

   (2)、當處于第二屏時 第二個ScrollView已經滑動到頂部并且滑動方向是往下滑動,這個時候滑動事件交給父view處理,根據滑動事件顯示出第一個ScrollView。

   (3)、當手指離開屏幕時,根據滑動速度來決定是回彈到第一個ScrollView還是第二個ScrollView,通過VelocityTracker來獲取滑動速度。

3、一些細節(jié)的處理

        (1)、如果仔細看觀察淘寶的實現效果你會發(fā)現,當你滑動到剛剛看到 “繼續(xù)拖動,查看圖文詳情”的時候,手指抬起,然后再按下重新向上拖動你會發(fā)現,第二頁并不會劃出來,而是停留在了“繼續(xù)拖動,查看圖文詳情”的底部,京東的效果也是一樣。這樣用戶體驗不太好,我們來優(yōu)化一下。其實通過查看ScrollView的源碼可以看出來,這是因為ScrollView類的onTouchEvent方法的默認實現,調用了parent.requestDisallowInterceptTouchEvent(true)方法 阻止了我們攔截事件,導致我們父view的onInterceptTouchEvent方法無法執(zhí)行,也就攔截不到事件,攔截不到事件我們的onTouchEvent就無法執(zhí)行,onTouchEvent無法執(zhí)行,我們寫在onTouchEvent里面的滾動邏輯就執(zhí)行不到了,導致了上面我們看到的劃不動的效果。解決方法就是,我們需要重寫dispatchTouchEvent()方法,防止子view干擾我們,這樣我們滑動的時候就可以一氣呵成了。代碼如下:

@Override  public boolean dispatchTouchEvent(MotionEvent ev) {   //防止子View禁止父view攔截事件   this.requestDisallowInterceptTouchEvent(false);   return super.dispatchTouchEvent(ev);  } 

      (2)、監(jiān)聽ScrollView滑動事件的問題

          ScrollView沒有提供滾動事件的監(jiān)聽方法,也就沒法判斷是否滾動到了頂部,或者底部,這里我們繼承ScrollView 自己實現滾動事件監(jiān)聽。

/**  * Created by baoyunlong on 16/6/8.  */ public class MyScrollView extends ScrollView {  private static String TAG=MyScrollView.class.getName();  public void setScrollListener(ScrollListener scrollListener) {   this.mScrollListener = scrollListener;  }  private ScrollListener mScrollListener;  public MyScrollView(Context context) {   super(context);  }  public MyScrollView(Context context, AttributeSet attrs) {   super(context, attrs);  }  public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {   super(context, attrs, defStyleAttr);  }  @Override  public boolean onTouchEvent(MotionEvent ev) {   switch (ev.getAction()){    case MotionEvent.ACTION_MOVE:     if(mScrollListener!=null){      int contentHeight=getChildAt(0).getHeight();      int scrollHeight=getHeight();      int scrollY=getScrollY();      mScrollListener.onScroll(scrollY);      if(scrollY+scrollHeight>=contentHeight||contentHeight<=scrollHeight){       mScrollListener.onScrollToBottom();      }else {       mScrollListener.notBottom();      }      if(scrollY==0){       mScrollListener.onScrollToTop();      }     }     break;   }   boolean result=super.onTouchEvent(ev);   requestDisallowInterceptTouchEvent(false);   return result;  }  public interface ScrollListener{   void onScrollToBottom();   void onScrollToTop();   void onScroll(int scrollY);   void notBottom();  } 

4、完整代碼如下

/**  * Created by baoyunlong on 16/6/8.  */ public class PullUpToLoadMore extends ViewGroup {  public static String TAG = PullUpToLoadMore.class.getName();  MyScrollView topScrollView, bottomScrollView;  VelocityTracker velocityTracker = VelocityTracker.obtain();  Scroller scroller = new Scroller(getContext());  int currPosition = 0;  int position1Y;  int lastY;  public int scaledTouchSlop;//最小滑動距離  int speed = 200;  boolean isIntercept;  public boolean bottomScrollVIewIsInTop = false;  public boolean topScrollViewIsBottom = false;  public PullUpToLoadMore(Context context) {   super(context);   init();  }  public PullUpToLoadMore(Context context, AttributeSet attrs) {   super(context, attrs);   init();  }  public PullUpToLoadMore(Context context, AttributeSet attrs, int defStyleAttr) {   super(context, attrs, defStyleAttr);   init();  }  private void init() {   post(new Runnable() {    @Override    public void run() {     topScrollView = (MyScrollView) getChildAt(0);     bottomScrollView = (MyScrollView) getChildAt(1);     topScrollView.setScrollListener(new MyScrollView.ScrollListener() {      @Override      public void onScrollToBottom() {       topScrollViewIsBottom = true;      }      @Override      public void onScrollToTop() {      }      @Override      public void onScroll(int scrollY) {      }      @Override      public void notBottom() {       topScrollViewIsBottom = false;      }     });     bottomScrollView.setScrollListener(new MyScrollView.ScrollListener() {      @Override      public void onScrollToBottom() {      }      @Override      public void onScrollToTop() {      }      @Override      public void onScroll(int scrollY) {       if (scrollY == 0) {        bottomScrollVIewIsInTop = true;       } else {        bottomScrollVIewIsInTop = false;       }      }      @Override      public void notBottom() {      }     });     position1Y = topScrollView.getBottom();     scaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();    }   });  }  @Override  public boolean dispatchTouchEvent(MotionEvent ev) {   //防止子View禁止父view攔截事件   this.requestDisallowInterceptTouchEvent(false);   return super.dispatchTouchEvent(ev);  }  @Override  public boolean onInterceptTouchEvent(MotionEvent ev) {   int y = (int) ev.getY();   switch (ev.getAction()) {    case MotionEvent.ACTION_DOWN:     lastY = y;     break;    case MotionEvent.ACTION_MOVE:     //判斷是否已經滾動到了底部     if (topScrollViewIsBottom) {      int dy = lastY - y;      //判斷是否是向上滑動和是否在第一屏      if (dy > 0 && currPosition == 0) {       if (dy >= scaledTouchSlop) {        isIntercept = true;//攔截事件        lastY=y;       }      }     }     if (bottomScrollVIewIsInTop) {      int dy = lastY - y;      //判斷是否是向下滑動和是否在第二屏      if (dy < 0 && currPosition == 1) {       if (Math.abs(dy) >= scaledTouchSlop) {        isIntercept = true;       }      }     }     break;   }   return isIntercept;  }  @Override  public boolean onTouchEvent(MotionEvent event) {   int y = (int) event.getY();   velocityTracker.addMovement(event);   switch (event.getAction()) {    case MotionEvent.ACTION_MOVE:     int dy = lastY - y;     if (getScrollY() + dy < 0) {      dy = getScrollY() + dy + Math.abs(getScrollY() + dy);     }     if (getScrollY() + dy + getHeight() > bottomScrollView.getBottom()) {      dy = dy - (getScrollY() + dy - (bottomScrollView.getBottom() - getHeight()));     }     scrollBy(0, dy);     break;    case MotionEvent.ACTION_UP:     isIntercept = false;     velocityTracker.computeCurrentVelocity(1000);     float yVelocity = velocityTracker.getYVelocity();     if (currPosition == 0) {      if (yVelocity < 0 && yVelocity < -speed) {       smoothScroll(position1Y);       currPosition = 1;      } else {       smoothScroll(0);      }     } else {      if (yVelocity > 0 && yVelocity > speed) {       smoothScroll(0);       currPosition = 0;      } else {       smoothScroll(position1Y);      }     }     break;   }   lastY = y;   return true;  }  @Override  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {   super.onMeasure(widthMeasureSpec, heightMeasureSpec);   measureChildren(widthMeasureSpec, heightMeasureSpec);  }  @Override  protected void onLayout(boolean changed, int l, int t, int r, int b) {   int childCount = getChildCount();   int childTop = t;   for (int i = 0; i < childCount; i++) {    View child = getChildAt(i);    child.layout(l, childTop, r, childTop + child.getMeasuredHeight());    childTop += child.getMeasuredHeight();   }  }  //通過Scroller實現彈性滑動  private void smoothScroll(int tartY) {   int dy = tartY - getScrollY();   scroller.startScroll(getScrollX(), getScrollY(), 0, dy);   invalidate();  }  @Override  public void computeScroll() {   if (scroller.computeScrollOffset()) {    scrollTo(scroller.getCurrX(), scroller.getCurrY());    postInvalidate();   }  } } 

源碼:

github地址

以上所述是小編給大家介紹的Android 仿淘寶、京東商品詳情頁向上拖動查看圖文詳情控件DEMO詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對武林網網站的支持!

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 安塞县| 湘潭县| 海口市| 莱芜市| 紫云| 曲麻莱县| 泸溪县| 宜宾市| 崇礼县| 秦皇岛市| 湖南省| 宜川县| 禄丰县| 慈利县| 昌乐县| 高淳县| 玉屏| 吉安市| 阳城县| 石棉县| 孝义市| 兰溪市| 柏乡县| 芜湖市| 双辽市| 桃江县| 庆元县| 阜新| 翁牛特旗| 绥滨县| 库尔勒市| 乡宁县| 平谷区| 惠安县| 新昌县| 舞阳县| 西和县| 车险| 南木林县| 四会市| 馆陶县|