>  기사  >  Java  >  Android 모방 Taobao, Jingdong 제품 세부 정보 페이지를 드래그하여 그래픽 세부 정보 제어 DEMO 세부 설명을 확인하세요.

Android 모방 Taobao, Jingdong 제품 세부 정보 페이지를 드래그하여 그래픽 세부 정보 제어 DEMO 세부 설명을 확인하세요.

高洛峰
高洛峰원래의
2017-02-08 17:10:332080검색

이 글에서는 위로 드래그하여 그래픽 세부정보를 볼 수 있는 Android 모방 Taobao 및 JD.com 제품 세부정보 페이지에 대한 자세한 DEMO 설명을 소개하며, 두 개의 scrollView가 수직 위치로 배열됩니다. 두 개의 scrollView는 viewGroup을 사용자 정의하고 슬라이딩 이벤트를 처리하여 제어됩니다. 안드로이드에서 사진과 텍스트 내용을 드래그해서 보는 지식에 관심있는 친구들은 함께 배워보세요

1. 타오바오 상품상세페이지 효과

Android 仿淘宝、京东商品详情页向上拖动查看图文详情控件DEMO详解

우리의 효과

Android 仿淘宝、京东商品详情页向上拖动查看图文详情控件DEMO详解

2. 구현 아이디어

두 개의 scrollView, 두 개의 scrollView가 수직으로 배열되고, 두 개의 scrollView의 수직 배열은 viewGroup 사용자 정의 및 슬라이딩 이벤트 처리를 통해 제어됩니다. 아래와 같이

3. 특정 구현

1. viewGroup 사용자 정의 레이아웃을 상속하고 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="继续拖动查看图文详情" 
      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. 슬라이딩 이벤트 처리

규칙은 다음과 같습니다.

(1 ) 첫 번째 화면에서 첫 번째 ScrollView가 아래쪽으로 미끄러지고 슬라이딩 방향이 위쪽인 경우 이때 슬라이딩 이벤트를 상위 뷰로 넘겨 처리해야 합니다. 즉, 이벤트를 가로채고 onInterceptTouchEvent가 반환되도록 해야 합니다. true 그런 다음 상위 뷰는 scrollBy() 메서드를 스크롤하여 두 번째 scrollView를 표시합니다.

(2) 두 번째 화면에서는 두 번째 ScrollView가 위로 미끄러지고 슬라이딩 방향이 아래로 미끄러지는 상태에서 슬라이딩 이벤트가 처리를 위해 상위 뷰로 넘겨집니다. 첫 번째는 슬라이딩 이벤트에 따라 표시됩니다.

(3) 손가락이 화면을 떠날 때 슬라이딩 속도에 따라 첫 번째 ScrollView로 리바운드할지 두 번째 ScrollView로 리바운드할지 결정하고 VelocityTracker를 통해 슬라이딩 속도를 구합니다.

3. 일부 세부정보 처리

(1) 타오바오 구현 효과를 잘 관찰해보면 방금 본 지점으로 슬라이드하면 '계속 드래그하세요. 그림과 텍스트의 세부 사항 " "을 누른 다음 다시 누르고 위쪽으로 드래그하면 두 번째 페이지가 그려지지 않고 "계속 드래그하여 그림 및 텍스트 세부 정보를 볼 수 있습니다"의 하단에 유지됩니다. ". JD.com의 효과도 마찬가지다. 이 사용자 경험은 그다지 좋지 않습니다. 최적화해 보겠습니다. 실제로 ScrollView의 소스 코드를 보면 이는 ScrollView 클래스의 onTouchEvent 메서드의 기본 구현이 이벤트를 가로채는 것을 방지하기 위해 parent.requestDisallowInterceptTouchEvent(true) 메서드를 호출하여 onInterceptTouchEvent가 발생하기 때문임을 알 수 있습니다. 이벤트를 수신할 수 없거나 이벤트를 차단할 수 없으면 onTouchEvent를 실행할 수 없으므로 onTouchEvent에 작성된 스크롤 로직을 실행할 수 없습니다. 위에서 본 것처럼 스크롤 효과가 불가능합니다. 해결책은 하위 뷰가 우리를 방해하지 않도록 dispatchTouchEvent() 메서드를 다시 작성하여 슬라이드할 때 한 번에 수행할 수 있도록 해야 한다는 것입니다. 코드는 다음과 같습니다.

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

(2) ScrollView의 슬라이딩 이벤트 모니터링 문제

ScrollView는 모니터링 방법을 제공하지 않습니다. 스크롤 이벤트의 경우 위쪽으로 스크롤했는지 아래쪽으로 스크롤했는지 확인할 방법이 없습니다. 여기서는 ScrollView를 상속하고 스크롤 이벤트 모니터링을 직접 구현합니다.

/** 
 * 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(); 
  } 
 } 
}

출처 code:

github 주소

위는 에디터가 소개하는 안드로이드 모방 타오바오, JD.com 제품 상세 페이지에 대한 자세한 설명입니다. 위로 드래그하시면 그래픽을 보실 수 있습니다. 그리고 텍스트 세부 사항은 DEMO를 제어하는 ​​데 도움이 되기를 바랍니다. 질문이 있는 경우 메시지를 남겨주시면 편집자가 제 시간에 답변해 드리겠습니다. 또한 PHP 중국어 웹사이트를 지원해 주신 모든 분들께 감사드립니다!

더 많은 Android 모방 Taobao 및 JD.com 제품 세부 정보 페이지를 보려면 위로 드래그하여 그래픽 세부 정보를 확인하고 DEMO를 제어하여 자세한 설명을 보려면 PHP 중국어 웹사이트를 주목하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.