Dieser Artikel stellt Ihnen die detaillierte DEMO-Erklärung der Produktdetailseite von Android-Imitationen von Taobao und JD.com vor, indem Sie nach oben ziehen, um grafische Details anzuzeigen, und die beiden ScrollViews sind vertikal angeordnet zwei scrollViews werden durch Anpassen der viewGroup-Anordnung und der Behandlung von Gleitereignissen gesteuert. Freunde, die sich für das Ziehen interessieren, um Bild- und Textdetails in Android anzuzeigen, sollten gemeinsam lernen
1. Taobao-Produktdetailseiteneffekt
Unsere Wirkung
2. Umsetzungsideen
Verwendung zwei scrollViews, zwei scrollViews sind vertikal angeordnet, und die vertikale Anordnung der beiden scrollViews wird durch Anpassen der viewGroup sowie durch die Verarbeitung von Gleitereignissen gesteuert. Wie unten gezeigt
3. Spezifische Implementierung
1. Erben Sie das benutzerdefinierte ViewGroup-Layout und überschreiben Sie die Methoden onMeasure() und onLayout Die onLayout-Methode Vervollständigen Sie das vertikale Layout der beiden Sub-ScrollViews. Der Code lautet wie folgt:
Layoutdatei:
<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>
Code:
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. Umgang mit Gleitereignissen
Die Regeln lauten wie folgt:
(1), wenn in Auf dem ersten Bildschirm ist die erste ScrollView nach unten gerutscht und die Schieberichtung ist nach oben. Zu diesem Zeitpunkt sollte das Schiebeereignis zur Verarbeitung an die übergeordnete Ansicht übergeben werden Das Ereignis sollte abgefangen werden und onInterceptTouchEvent gibt true zurück. Dann scrollt die übergeordnete Ansicht durch die scrollBy()-Methode und zeigt die zweite scrollView an.
(2) Wenn auf dem zweiten Bildschirm die zweite ScrollView nach oben verschoben wurde und die Schieberichtung nach unten verschoben wird, wird das Schiebeereignis zur Verarbeitung an die übergeordnete Ansicht übergeben Das erste wird entsprechend dem Sliding-Ereignis angezeigt.
(3) Wenn der Finger den Bildschirm verlässt, entscheiden Sie basierend auf der Gleitgeschwindigkeit, ob Sie zur ersten ScrollView oder zur zweiten ScrollView zurückkehren möchten, und erhalten Sie die Gleitgeschwindigkeit über VelocityTracker.
3. Verarbeitung einiger Details
(1) Wenn Sie den Implementierungseffekt von Taobao sorgfältig beobachten, werden Sie feststellen, dass Sie an den Punkt gelangen, an dem Sie gerade „Weiterziehen, anzeigen“ gesehen haben Um die Details des Bilds und des Textes anzuzeigen, heben Sie Ihren Finger an, drücken Sie und ziehen Sie ihn erneut nach oben. Sie werden feststellen, dass die zweite Seite nicht herausgezogen wird, sondern am unteren Rand von „Ziehen Sie weiter, um Bild- und Textdetails anzuzeigen“ angezeigt wird ". Der Effekt von JD.com Das Gleiche. Diese Benutzererfahrung ist nicht sehr gut. Lassen Sie uns sie optimieren. Wenn wir uns den Quellcode von ScrollView ansehen, können wir tatsächlich erkennen, dass dies daran liegt, dass die Standardimplementierung der onTouchEvent-Methode der ScrollView-Klasse die Methode parent.requestDisallowInterceptTouchEvent(true) aufruft, um zu verhindern, dass wir das Ereignis abfangen, was zu onInterceptTouchEvent führt Die Methode unserer übergeordneten Ansicht kann nicht ausgeführt werden und wird daher nicht abgefangen. Wenn das Ereignis nicht empfangen werden kann, kann unser OnTouchEvent nicht ausgeführt werden im Unfähigkeit-zu-Scrollen-Effekt, wie wir oben gesehen haben. Die Lösung besteht darin, dass wir die Methode „dispatchTouchEvent()“ neu schreiben müssen, um zu verhindern, dass die Unteransicht uns stört, sodass wir dies auf einmal tun können, wenn wir gleiten. Der Code lautet wie folgt:
@Override public boolean dispatchTouchEvent(MotionEvent ev) { //防止子View禁止父view拦截事件 this.requestDisallowInterceptTouchEvent(false); return super.dispatchTouchEvent(ev); }
(2) Probleme bei der Überwachung von ScrollView-Schiebeereignissen
ScrollView bietet keine Überwachungsmethode für Scrolling-Ereignisse Es gibt keine Möglichkeit zu beurteilen, ob das Scrollen den oberen oder unteren Rand erreicht hat. Hier erben wir ScrollView und implementieren selbst die Scroll-Ereignisüberwachung.
/** * 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. Der vollständige Code lautet wie folgt:
/** * 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(); } } }
Quellcode:
Github-Adresse
Das Obige ist die vom Herausgeber eingeführte Android-Imitationsseite für Taobao- und JD-Produktdetails. Ziehen Sie nach oben, um die DEMO mit grafischen Details anzuzeigen. Ich hoffe, dass es für Sie hilfreich ist. Wenn Sie Fragen haben, hinterlassen Sie mir bitte eine Nachricht und der Herausgeber wird Ihnen rechtzeitig antworten. Ich möchte mich auch bei Ihnen allen für Ihre Unterstützung der chinesischen PHP-Website bedanken!
Für weitere Android-Imitationsseiten mit Taobao- und JD.com-Produktdetails ziehen Sie nach oben, um grafische Details anzuzeigen und die DEMO für detaillierte Erklärungen zu steuern. Weitere Informationen zu verwandten Artikeln finden Sie auf der chinesischen PHP-Website!