閱讀545 返回首頁    go 魔獸


Android 仿美團網,大眾點評購買框懸浮效果之修改版

如果快速滑動界麵,顯示懸浮框的時候會出現一卡的現象,有些朋友說有時候會出現兩個布局的情況,特別是對ScrollView滾動的Y值得監聽,我還使用了Handler來獲取,還有朋友給我介紹了Scrolling Tricks這個東西,我下載試了下,確實美團網,大眾點評的購買框用的是這種效果,但是Scrolling Tricks隻能在API11以上使用,這個有點小悲劇,然後我做了下修改,並將實現思路分享給大家,實現起來很簡單

首先還是要先對ScrollView進行滾動監聽,直接在onScrollChanged()方法中就能獲取滾動的Y值,之前那篇文章使用了Handler,走彎路了,直接看代碼吧

  1. package com.example.meituandemo;  
  2.   
  3. import android.content.Context;  
  4. import android.util.AttributeSet;  
  5. import android.widget.ScrollView;  
  6. /** 
  7.  * @blog https://blog.csdn.net/xiaanming 
  8.  *  
  9.  * @author xiaanming 
  10.  * 
  11.  */  
  12. public class MyScrollView extends ScrollView {  
  13.     private OnScrollListener onScrollListener;  
  14.       
  15.     public MyScrollView(Context context) {  
  16.         this(context, null);  
  17.     }  
  18.       
  19.     public MyScrollView(Context context, AttributeSet attrs) {  
  20.         this(context, attrs, 0);  
  21.     }  
  22.   
  23.     public MyScrollView(Context context, AttributeSet attrs, int defStyle) {  
  24.         super(context, attrs, defStyle);  
  25.     }  
  26.       
  27.     /** 
  28.      * 設置滾動接口 
  29.      * @param onScrollListener 
  30.      */  
  31.     public void setOnScrollListener(OnScrollListener onScrollListener) {  
  32.         this.onScrollListener = onScrollListener;  
  33.     }  
  34.       
  35.       
  36.     @Override  
  37.     public int computeVerticalScrollRange() {  
  38.         return super.computeVerticalScrollRange();  
  39.     }  
  40.       
  41.   
  42.     @Override  
  43.     protected void onScrollChanged(int l, int t, int oldl, int oldt) {  
  44.         super.onScrollChanged(l, t, oldl, oldt);  
  45.         if(onScrollListener != null){  
  46.             onScrollListener.onScroll(t);  
  47.         }  
  48.     }  
  49.   
  50.   
  51.   
  52.     /** 
  53.      *  
  54.      * 滾動的回調接口 
  55.      *  
  56.      * @author xiaanming 
  57.      * 
  58.      */  
  59.     public interface OnScrollListener{  
  60.         /** 
  61.          * 回調方法, 返回MyScrollView滑動的Y方向距離 
  62.          * @param scrollY 
  63.          *              、 
  64.          */  
  65.         public void onScroll(int scrollY);  
  66.     }  
  67.       
  68.       
  69.   
  70. }  
接下來看看主界麵的布局文件
  1. <LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"  
  2.     android:id="@+id/parent_layout"  
  3.     xmlns:tools="https://schemas.android.com/tools"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     android:orientation="vertical" >  
  7.   
  8.     <ImageView  
  9.         android:id="@+id/imageView1"  
  10.         android:layout_width="match_parent"  
  11.         android:layout_height="45dip"  
  12.         android:scaleType="centerCrop"  
  13.         android:src="@drawable/navigation_bar" />  
  14.   
  15.     <com.example.meituandemo.MyScrollView  
  16.         android:id="@+id/scrollView"  
  17.         android:layout_width="fill_parent"  
  18.         android:layout_height="fill_parent" >  
  19.   
  20.         <FrameLayout  
  21.             android:layout_width="match_parent"  
  22.             android:layout_height="wrap_content" >  
  23.   
  24.             <LinearLayout  
  25.                 android:layout_width="match_parent"  
  26.                 android:layout_height="wrap_content"  
  27.                 android:orientation="vertical" >  
  28.   
  29.                 <ImageView  
  30.                     android:id="@+id/iamge"  
  31.                     android:layout_width="match_parent"  
  32.                     android:layout_height="wrap_content"  
  33.                     android:background="@drawable/pic"  
  34.                     android:scaleType="centerCrop" />  
  35.   
  36.                 <include  
  37.                     android:id="@+id/buy"  
  38.                     layout="@layout/buy_layout" />  
  39.   
  40.                 <ImageView  
  41.                     android:layout_width="match_parent"  
  42.                     android:layout_height="wrap_content"  
  43.                     android:background="@drawable/one"  
  44.                     android:scaleType="centerCrop" />  
  45.   
  46.                 <ImageView  
  47.                     android:layout_width="match_parent"  
  48.                     android:layout_height="wrap_content"  
  49.                     android:background="@drawable/one"  
  50.                     android:scaleType="centerCrop" />  
  51.   
  52.                 <ImageView  
  53.                     android:layout_width="match_parent"  
  54.                     android:layout_height="wrap_content"  
  55.                     android:background="@drawable/one"  
  56.                     android:scaleType="centerCrop" />  
  57.             </LinearLayout>  
  58.   
  59.             <include  
  60.                 android:id="@+id/top_buy_layout"  
  61.                 layout="@layout/buy_layout" />  
  62.         </FrameLayout>  
  63.     </com.example.meituandemo.MyScrollView>  
  64.   
  65. </LinearLayout>  

下麵是布局的效果圖


從主界麵的布局你可以看出,我們在上麵放置了一個購買的布局,可能你會想,先讓上麵的布局隱藏起來,等下麵的布局滑動上來就將其顯示出來,如果這樣子就跟我之前寫的那篇文章差不多,效果不是很棒,所以這篇修改版的肯定不是這樣子的,我們還是先看主界麵的代碼吧

  1. package com.example.meituandemo;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.view.ViewTreeObserver.OnGlobalLayoutListener;  
  6. import android.widget.LinearLayout;  
  7.   
  8. import com.example.meituandemo.MyScrollView.OnScrollListener;  
  9.   
  10. /** 
  11.  * @blog https://blog.csdn.net/xiaanming 
  12.  *  
  13.  * @author xiaanming 
  14.  * 
  15.  */  
  16. public class MainActivity extends Activity implements OnScrollListener{  
  17.     /** 
  18.      * 自定義的MyScrollView 
  19.      */  
  20.     private MyScrollView myScrollView;  
  21.     /** 
  22.      * 在MyScrollView裏麵的購買布局 
  23.      */  
  24.     private LinearLayout mBuyLayout;  
  25.     /** 
  26.      * 位於頂部的購買布局 
  27.      */  
  28.     private LinearLayout mTopBuyLayout;  
  29.       
  30.   
  31.     @SuppressWarnings("deprecation")  
  32.     @Override  
  33.     protected void onCreate(Bundle savedInstanceState) {  
  34.         super.onCreate(savedInstanceState);   
  35.         setContentView(R.layout.activity_main);  
  36.           
  37.         myScrollView = (MyScrollView) findViewById(R.id.scrollView);  
  38.         mBuyLayout = (LinearLayout) findViewById(R.id.buy);  
  39.         mTopBuyLayout = (LinearLayout) findViewById(R.id.top_buy_layout);  
  40.           
  41.         myScrollView.setOnScrollListener(this);  
  42.           
  43.         //當布局的狀態或者控件的可見性發生改變回調的接口  
  44.         findViewById(R.id.parent_layout).getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {  
  45.               
  46.             @Override  
  47.             public void onGlobalLayout() {  
  48.                 //這一步很重要,使得上麵的購買布局和下麵的購買布局重合  
  49.                 onScroll(myScrollView.getScrollY());  
  50.                   
  51.             }  
  52.         });  
  53.     }  
  54.   
  55.   
  56.   
  57.   
  58.     @Override  
  59.     public void onScroll(int scrollY) {  
  60.         int mBuyLayout2ParentTop = Math.max(scrollY, mBuyLayout.getTop());  
  61.         mTopBuyLayout.layout(0, mBuyLayout2ParentTop, mTopBuyLayout.getWidth(), mBuyLayout2ParentTop + mTopBuyLayout.getHeight());  
  62.     }  
  63.   
  64.   
  65.   
  66. }  
主界麵就短短的幾行代碼,可能看完這些代碼你還是沒有明白到底是怎麼做到的,沒關係,我給大家說說,其實我們是讓上麵的購買布局和下麵的購買布局重合起來了,layout()這個方法是確定View的大小和位置的,然後將其繪製出來,裏麵的四個參數分別是View的四個點的坐標,他的坐標不是相對屏幕的原點,而且相對於他的父布局來說的,
我們在主頁麵最外層的ViewGroup添加了布局狀態改變的監聽器,當繪製完了屏幕會回調到方法onGlobalLayout()中,我們在onGlobalLayout()方法中手動調用了下onScroll()方法,剛開始myScrollView.getScrollY()等於0,所以說當scrollY小於mBuyLayout.getTop()的時候,上麵的購買布局的上邊緣到myScrollView的上邊緣的距離等於mBuyLayout.getTop()(即下麵布局的上邊緣到myScrollView的上邊緣)所以剛開始上麵的購買布局和下麵的購買布局重合了。
當myScrollView向上滾動,而上麵購買布局的上邊緣始終要和myScrollView的上邊緣保持mBuyLayout.getTop()這個距離,所以上麵的購買布局也跟著向上滾動,當scrollY大於mBuyLayout.getTop()的時候,表示購買布局上邊緣滑動到了導航欄布局,所以此時購買布局的上邊緣與myScrollView的上邊緣始終要保持scrollY這個距離,所以購買布局才會一直在導航欄下麵,就好像粘住了一樣,不知道你了解了沒有?好了,不過根據這種思路你也可以剛開始使用一個懸浮框來覆蓋在下麵的購買布局上麵,然後onScroll()方法中更新懸浮框的位置,不過懸浮框的x,y不是相對於父布局的,這點要注意下,這樣子也能實現效果,不過相對於此,要複雜的多,所以我們遇到類似的功能直接使用這種就行了,簡潔明了,好了,你是不迫不及待的想看下效果,那我們接下來就運行下程序吧


運行程序你會發現,無論我們怎麼滑動,都不會出現之前那篇文章的那些情況,很流暢吧,這跟美團,大眾點評的效果完全一致,好了,修改版的講解就到這裏結束了,有問題的請在下麵留言,我會為大家解答的!

項目源碼,點擊下載

最後更新:2017-04-03 12:56:01

  上一篇:go NYOJ545-Metric Matrice
  下一篇:go Apache Portable Runtime which allows optimal performance in production environments was not found