Android自訂LinearLayout實現淘寶詳情頁_Android

來源:互聯網
上載者:User

1.簡單說明

淘寶詳情頁就不用我一一介紹了,昨天逛淘寶看到這個效果時,讓我想起了去年剛學習Android只會使用現成的時候,當時在網上找了一個這種效果的使用了,並不懂怎麼實現的。現在就看到一種效果就想自己實現一下,我想這就是剛接觸某個知識時的好奇心吧

說走咱就走啊,本文只是介紹一種實現思路,網上也已經有了很多種實現方式,有問題請指正

效果圖(我有很用心的找美女圖的)

2.實現思路

繼承LinearLayout,設定方向為垂直
控制項中有兩個ScrollView,至於為什麼要使用ScrollView,主要是因為內容超過一頁時省去自己處理滑動
關鍵是事件分發處理。監聽兩個ScrollView的滑動事件,當第一頁滑動到底部時,再向上拖動時,攔截事件,判斷距離,超過設定值時,滑動到第二頁,否則回彈;同理,當第二頁滑動到頂部時,再向下拖動時,攔截事件,判斷距離,超過設定值時,滑動到第一頁,否則回彈(還有很多細節需要結合代碼講解)
關於回彈和滑動換頁使用的是Scroller,對於Scroller的使用,本文不做過多解釋

3.實現

3.1重寫ScrollView

根據實現思路,我們需要監聽ScrollView是否滑動到頂部和底部,但是ScrollView的setOnScrollChangeListener()方法在api23才添加。主要是重寫ScrollViewonScrollChanged(int l, int t, int oldl, int oldt)方法。

l:當前水平方向滾動值,和getScrollX()相等
t:當前豎直方向滾動值,和getScrollY()相等
oldl:上一次水平滾動值
oldt:上一次豎直滾動值

監聽介面:

public interface OnScrollEndListener { void scrollToBottom(View view); void scrollToTop(View view); void scrollToMiddle(View view); }

onScrollChanged方法

 @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if(t == 0){  if (mOnScrollBottomListener != null) {  mOnScrollBottomListener.scrollToTop(this);  } } else if(t + getMeasuredHeight() >= getChildAt(0).getMeasuredHeight()){  if (mOnScrollBottomListener != null) {  mOnScrollBottomListener.scrollToBottom(this);  } } else {  if (mOnScrollBottomListener != null) {  mOnScrollBottomListener.scrollToMiddle(this);  } } }

3.2重寫onMeasure方法、page的擷取與設定

顯示調用第二個自孩子的測量方法,不然尺寸有可能為0

 @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); /**  * 顯示調用第二個自孩子的測量方法,不然尺寸有可能為0  */ View child2 = getChildAt(1); if (child2 != null) {  child2.measure(widthMeasureSpec, heightMeasureSpec); } }

在onFinishInflate中初始化兩個頁面

@Override protected void onFinishInflate() { super.onFinishInflate(); if(getChildCount() == 2){  View child1 = getChildAt(0);  if (child1 instanceof ScrollEndScrollView){  scrollView1 = (ScrollEndScrollView) child1;  }  View child2 = getChildAt(1);  if(child2 instanceof ScrollEndScrollView){  scrollView2 = (ScrollEndScrollView) child2;  } } initEvent(); }

為兩個版面設定滑動監聽

private ScrollEndScrollView.OnScrollEndListener scrollEndListener = new ScrollEndScrollView.OnScrollEndListener() { @Override public void scrollToBottom(View view) {  if(view == scrollView1){  isToBotttom = true;  } } @Override public void scrollToTop(View view) {  if(view == scrollView2){  isToTop = true;  } } @Override public void scrollToMiddle(View view) {  if(view == scrollView1){  isToBotttom = false;  }  if(view == scrollView2){  isToTop = false;  } } };

3.3Scroller使用的幾步

Scroller的英文解釋是:
This class encapsulates scrolling. You can use scrollers (Scroller or OverScroller) to collect the data you need to produce a scrolling animation—for example, in response to a fling gesture. Scrollers track scroll offsets for you over time, but they don't automatically apply those positions to your view. It's your responsibility to get and apply new coordinates at a rate that will make the scrolling animation look smooth.

此類封裝滾動。您可以使用捲軸(滾輪或OverScroller)收集你需要製作一個滾動的動畫,例如,響應一扔手勢的資料。捲軸為您跟蹤滾動位移量隨著時間的推移,但他們不會自動將新的位置設定到View中。你的任務是擷取並使用一個合適的速度,使滾動動畫看起來更平滑。

簡而言之,有關滑動的你都可以使用這個實現。

需要重寫的方法

@Override public void computeScroll() { super.computeScroll(); //先判斷mScroller滾動是否完成 if (mScroller.computeScrollOffset()) {  //這裡調用View的scrollTo()完成實際的滾動  scrollTo(mScroller.getCurrX(), mScroller.getCurrY());  //必須調用該方法,否則不一定能看到滾動效果  postInvalidate(); } }

輔助方法

 //調用此方法設定滾動的相對位移 public void smoothScrollBy(int dx, int dy) { //設定mScroller的滾動位移量 mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy, Math.max(300, Math.abs(dy))); invalidate();//這裡必須調用invalidate()才能保證computeScroll()會被調用,否則不一定會重新整理介面,看不到滾動效果 }//調用此方法滾動到目標位置 public void smoothScrollTo(int fx, int fy) { int dx = fx - mScroller.getFinalX(); int dy = fy - mScroller.getFinalY(); smoothScrollBy(dx, dy); }

3.4事件分發

最關鍵的部分,邏輯稍複雜,細節處理較多。這裡重寫dispatchTouchEvent。

顯示第一頁時
未滑動到底部,事件由scrollView1自己處理
滑動到底部時,如果繼續向上拖動,攔截事件,父控制項處理滑動;繼續向下拖動時,如果父控制項(即該控制項)當前滾動最後位置(mScroller.getFinalY())不為0, 如果父控制項繼續滾動不會出現負值時(出現負值時會導致頭部空白,因為這時是父控制項控制,scrollView1不可滑動),不攔截事件,父控制項處理滑動,否則,強制滑動到0位置,並把事件下發給子控制項

顯示第二頁時
未滑動到最頂部時,事件由scrollView2自己處理
滑動到頂部時,如果繼續向下拖動,攔截事件,父控制項處理滑動;繼續向上拖動時,如果父控制項當前滾動位置小於第一頁高度,攔截事件,父控制項處理滑動,否則,滑動到第二頁起始位置,並把事件下發給子控制項
ACTION_MOVE中進行事件分發,ACTION_UP中進行切換頁面、回彈
關於使用scroller滑動,實現彈性效果,簡單實現請看這裡簡單的彈性實現代碼

@Override public boolean dispatchTouchEvent(MotionEvent ev) { int action = ev.getAction(); int yPosition = (int) ev.getY(); switch (action) {  case MotionEvent.ACTION_DOWN:  mScroller.abortAnimation();  mLastY = yPosition;  mMoveY = 0;  break;  case MotionEvent.ACTION_MOVE:  mMoveY = (mLastY - yPosition);  mLastY = yPosition;  if(isToBotttom){   if(mMoveY > 0){   //向上   smoothScrollBy(0, mMoveY);   return true;   } else {   //向下   if(mScroller.getFinalY() != 0){    //這是出於第一頁和第二頁顯示串連處    if(getScrollY() + mMoveY > 0){    smoothScrollBy(0, mMoveY);    return true;    } else{    smoothScrollTo(0, 0);    return super.dispatchTouchEvent(ev);    }   }   }  }  else if(isToTop){   if(mMoveY < 0){   //向下   smoothScrollBy(0, mMoveY);   return true;   } else {   //向上   if(mScroller.getFinalY() < scrollView1.getHeight()){    //這是出於第一頁和第二頁顯示串連處    smoothScrollBy(0, mMoveY);    return true;   } else {    smoothScrollTo(0, scrollView1.getHeight());    return super.dispatchTouchEvent(ev);   }   }  }  //處理快速滑動時兩頁覆蓋問題  if(pageIndex == 0){   smoothScrollTo(0, 0);  } else if(pageIndex == 1){   smoothScrollTo(0, scrollView1.getHeight());  }  break;  case MotionEvent.ACTION_UP:  case MotionEvent.ACTION_CANCEL:  if(isToBotttom){   if(Math.abs(getScrollY()) > TO_NEXT_PAGE_HEIGHT){   //移動到第二頁   pageIndex = 1;   smoothScrollTo(0, scrollView1.getHeight());   isToBotttom = false;   isToTop = true;   } else {   //回彈   smoothScrollBy(0, -mScroller.getFinalY());   }  } else if(isToTop){   if(scrollView1.getHeight() - getScrollY() > TO_NEXT_PAGE_HEIGHT){   //移動到第一頁   pageIndex = 0;   smoothScrollTo(0, 0);   isToBotttom = true;   isToTop = false;   } else {   //回彈   smoothScrollTo(0, scrollView1.getHeight());   }  }  break;  default:  break; } return super.dispatchTouchEvent(ev); }

4.總結

實現該控制項,需要掌握的知識點主要是自訂控制項的基本步驟、Scroller的基本使用和事件分發,當然這裡最關鍵的處理還是事件分發。開頭也說了,雖然這個有很多人實現過了,但還是想用自己的方式實現一遍。大笑三聲,哈哈哈,又實現一個自訂控制項…博主還在自訂控制項學習階段,請謹慎使用該控制項到項目中。

5.下載

https://github.com/LineChen/TwoPageLayout

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.