2014-01-29 65 views
13

我有一個視圖的概念。請指導我如何實現它。請檢查線框。 enter image description here多個頁面瀏覽器的滾動效果

我已經看過FadingActionBar,但它似乎沒有幫助。問題是我有多個viewpage在屏幕上,並沒有去試圖達到預期的結果。如果我能夠實現一個很酷的轉換/視差效果,那將是超級棒的。

任何輸入將不勝感激。

EDIT1:

的選項卡放在一個PagerTabStrip與它下面的Viewpager迷上了。這裏的嘗試是滾動視圖並將PagerTabStrip停靠到ActionBar,然後向下滾動以顯示ImageViewPager。

+1

OOOOOO這看起來有趣的嘗試! –

+0

@JakeWharton - 如果你能把這個脫下來,我會非常感激你:D – Neo

回答

14

所以,這可以很容易實現,但它需要一個小技巧,實際上更像是一種幻覺。另外,我將使用一個ListView代替ScrollView我的「滾動內容」,主要是因爲它更容易使用在這種情況下和我的標籤我將使用this open sourced library.

首先,你需要可以存儲給定索引的y座標的View。此自定義View將放置在底部ViewPager之上,並顯示爲每個ListView的「真實」標題。您需要記住ViewPager中每個頁面的標題的y座標,以便用戶稍後可以在它們之間滑動時恢復它們。我將擴大這以後,但現在這裏是一個View應該是什麼樣子:

CoordinatedHeader

public class CoordinatedHeader extends FrameLayout { 

    /** The float array used to store each y-coordinate */ 
    private final float[] mCoordinates = new float[5]; 

    /** True if the header is currently animating, false otherwise */ 
    public boolean mAnimating; 

    /** 
    * Constructor for <code>CoordinatedHeader</code> 
    * 
    * @param context The {@link Context} to use 
    * @param attrs The attributes of the XML tag that is inflating the view 
    */ 
    public CoordinatedHeader(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    /** 
    * Animates the header to the stored y-coordinate at the given index 
    * 
    * @param index The index used to retrieve the stored y-coordinate 
    * @param duration Sets the duration for the underlying {@link Animator} 
    */ 
    public void restoreCoordinate(int index, int duration) { 
     // Find the stored value for the index 
     final float y = mCoordinates[index]; 
     // Animate the header to the y-coordinate 
     animate().y(y).setDuration(duration).setListener(mAnimatorListener).start(); 
    } 

    /** 
    * Saves the given y-coordinate at the specified index, the animates the 
    * header to the requested value 
    * 
    * @param index The index used to store the given y-coordinate 
    * @param y The y-coordinate to save 
    */ 
    public void storeCoordinate(int index, float y) { 
     if (mAnimating) { 
      // Don't store any coordinates while the header is animating 
      return; 
     } 
     // Save the current y-coordinate 
     mCoordinates[index] = y; 
     // Animate the header to the y-coordinate 
     restoreCoordinate(index, 0); 
    } 

    private final AnimatorListener mAnimatorListener = new AnimatorListener() { 

     /** 
     * {@inheritDoc} 
     */ 
     @Override 
     public void onAnimationCancel(Animator animation) { 
      mAnimating = false; 
     } 

     /** 
     * {@inheritDoc} 
     */ 
     @Override 
     public void onAnimationEnd(Animator animation) { 
      mAnimating = false; 
     } 

     /** 
     * {@inheritDoc} 
     */ 
     @Override 
     public void onAnimationRepeat(Animator animation) { 
      mAnimating = true; 
     } 

     /** 
     * {@inheritDoc} 
     */ 
     @Override 
     public void onAnimationStart(Animator animation) { 
      mAnimating = true; 
     } 
    }; 

} 

現在你可以爲你ActivityFragment創建主佈局。該佈局包含底部ViewPagerCoordinatedHeader;其中包括底部ViewPager和標籤。

主要佈局

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" > 

    <android.support.v4.view.ViewPager 
     android:id="@+id/activity_home_pager" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" /> 

    <org.seeingpixels.example.widget.CoordinatedHeader 
     android:id="@+id/activity_home_header" 
     android:layout_width="match_parent" 
     android:layout_height="250dp" > 

     <android.support.v4.view.ViewPager 
      android:id="@+id/activity_home_header_pager" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" /> 

     <com.astuetz.viewpager.extensions.PagerSlidingTabStrip 
      android:id="@+id/activity_home_tabstrip" 
      android:layout_width="match_parent" 
      android:layout_height="48dp" 
      android:layout_gravity="bottom" 
      android:background="@android:color/white" /> 
    </org.seeingpixels.example.widget.CoordinatedHeader> 

</FrameLayout> 

你需要的是一個 「假」 頭唯一的其他佈局。這種佈局將被添加到每個ListView,給主幻想CoordinatedHeader錯覺是真實的。

注意重要的是,這個佈局的高度是一樣的,在主要佈局CoordinatedHeader,在這個例子中我使用250dp

假頭

<View xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="250dp" /> 

現在,你需要準備將被顯示在底部ViewPagerAbsListView.OnScrollListener連接到您的ListView控制CoordinatedHeader每個Fragment。這Fragment也應該創建時使用Fragment.setArguments通過一個唯一的索引。該索引應代表其在ViewPager中的位置。

注意我在本例中使用ListFragment

滾動內容Fragment

/** 
* {@inheritDoc} 
*/ 
@Override 
public void onViewCreated(View view, Bundle savedInstanceState) { 
    super.onViewCreated(view, savedInstanceState); 
    final Activity a = getActivity(); 

    final ListView list = getListView(); 
    // Add the fake header 
    list.addHeaderView(LayoutInflater.from(a).inflate(R.layout.view_fake_header, list, false)); 

    // Retrieve the index used to save the y-coordinate for this Fragment 
    final int index = getArguments().getInt("index"); 

    // Find the CoordinatedHeader and tab strip (or anchor point) from the main Activity layout 
    final CoordinatedHeader header = (CoordinatedHeader) a.findViewById(R.id.activity_home_header); 
    final View anchor = a.findViewById(R.id.activity_home_tabstrip); 

    // Attach a custom OnScrollListener used to control the CoordinatedHeader 
    list.setOnScrollListener(new OnScrollListener() { 

     @Override 
     public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, 
       int totalItemCount) { 

      // Determine the maximum allowed scroll height 
      final int maxScrollHeight = header.getHeight() - anchor.getHeight(); 

      // If the first item has scrolled off screen, anchor the header 
      if (firstVisibleItem != 0) { 
       header.storeCoordinate(index, -maxScrollHeight); 
       return; 
      } 

      final View firstChild = view.getChildAt(firstVisibleItem); 
      if (firstChild == null) { 
       return; 
      } 

      // Determine the offset to scroll the header 
      final float offset = Math.min(-firstChild.getY(), maxScrollHeight); 
      header.storeCoordinate(index, -offset); 
     } 

     @Override 
     public void onScrollStateChanged(AbsListView view, int scrollState) { 
      // Nothing to do 
     } 

    }); 
} 

最後,您需要設置Coordinated頭,當用戶使用ViewPager.OnPageChangeListener頁面之間揮筆,以恢復其y座標。

注意當您連接到PagerAdapter您底部ViewPager,它調用ViewPager.setOffscreenPageLimit和金額設置爲頁面的總量在PagerAdapter是非常重要的。這樣CoordinatedHeader可以立即存儲每個Fragment的y座標,否則會遇到不同步的問題。

主要Activity

/** 
* {@inheritDoc} 
*/ 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_home); 

    // Setup the top PagerAdapter 
    final PagerAdapter topAdapter = new PagerAdapter(getFragmentManager()); 
    topAdapter.buildData(DummyColorFragment.newInstance(Color.RED)); 
    topAdapter.buildData(DummyColorFragment.newInstance(Color.WHITE)); 
    topAdapter.buildData(DummyColorFragment.newInstance(Color.BLUE)); 

    // Setup the top pager 
    final ViewPager topPager = (ViewPager) findViewById(R.id.activity_home_header_pager); 
    topPager.setAdapter(topAdapter); 

    // Setup the bottom PagerAdapter 
    final PagerAdapter bottomAdapter = new PagerAdapter(getFragmentManager()); 
    bottomAdapter.buildData(DummyListFragment.newInstance(0)); 
    bottomAdapter.buildData(DummyListFragment.newInstance(1)); 
    bottomAdapter.buildData(DummyListFragment.newInstance(2)); 
    bottomAdapter.buildData(DummyListFragment.newInstance(3)); 
    bottomAdapter.buildData(DummyListFragment.newInstance(4)); 

    // Setup the bottom pager 
    final ViewPager bottomPager = (ViewPager) findViewById(R.id.activity_home_pager); 
    bottomPager.setOffscreenPageLimit(bottomAdapter.getCount()); 
    bottomPager.setAdapter(bottomAdapter); 

    // Setup the CoordinatedHeader and tab strip 
    final CoordinatedHeader header = (CoordinatedHeader) findViewById(R.id.activity_home_header); 
    final PagerSlidingTabStrip psts = (PagerSlidingTabStrip) findViewById(R.id.activity_home_tabstrip); 
    psts.setViewPager(bottomPager); 
    psts.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { 
     @Override 
     public void onPageScrollStateChanged(int state) { 
      if (state != ViewPager.SCROLL_STATE_IDLE) { 
       // Wait until the pager is idle to animate the header 
       return; 
      } 
      header.restoreCoordinate(bottomPager.getCurrentItem(), 250); 
     } 
    }); 
} 
+0

哇!該視頻看起來完全像我以後。在我實施它之後應該接受。非常感謝! – Neo

+0

嗨@adneal如果你提供這個項目,它會更有幫助。 –

+0

@DineshRaj所有的資源都在那裏,如果有特定的部分你想幫忙,我會很樂意回答這個問題。 – adneal

1

您也可以實現通過Android的ParallaxHeaderViewPager滾動標籤頭的一個很好的例子這種效果通過kmshack Github page

的示例代碼讓在這個Here Git Hub link

這裏是屏幕截圖 enter image description here

@adneal的解決方案也實現了滾動Tab標頭非常有用。

合這將幫助你

新的更新

請檢查這個答案 Google+ profile like scrolling Effect

+0

你能幫我做到這一點... @Ramz –

+0

@SaravanaKumarChinnaraj你只是想到我提供並導入項目的github頁面 – Ramz

+0

感謝您的重播以及工作。我做了下載和東西,但這個問題出現在那裏,當我運行該項目 –

0

我使用片段容器佈局,而不是viewpager與FadingActionBar。我也使用MaterialTabs庫。

內容佈局

<xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:background="?android:attr/windowBackground" 
    android:orientation="vertical"> 

    <it.neokree.materialtabs.MaterialTabHost 
     android:id="@+id/materialTabHost" 
     android:layout_width="match_parent" 
     android:layout_height="48dp" 
     app:accentColor="@color/second" 
     app:primaryColor="@color/actionbar_background" 
     app:textColor="#FFFFFF" /> 

    <FrameLayout 
     android:id="@+id/container" 
     android:layout_width="wrap_content" 
     android:layout_height="match_parent"> 

    </FrameLayout> 
</LinearLayout> 

活動

 @Override 
      protected void onCreate(Bundle savedInstanceState) { 
       super.onCreate(savedInstanceState); 

       FadingActionBarHelper helper = new FadingActionBarHelper() 
         .actionBarBackground(R.color.actionbar_background) 
         .headerLayout(R.layout.actionbar_header) 
         .contentLayout(R.layout.content_layout); 
       final View root = helper.createView(this); 
       setContentView(root); 
       helper.initActionBar(this); 
mTabHost = (MaterialTabHost) view.findViewById(R.id.materialTabHost); 
     //....... 
     } 
    @Override 
     public void onTabSelected(MaterialTab materialTab) { 
      int position = materialTab.getPosition(); 
      switch (position) { 
       case 0: 
        switchFragment(new ProfileFragment(), position); 
        break; 
       case 1: 
        switchFragment(new NotificationFragment(), position); 
        break; 
      } 
      mTabHost.setSelectedNavigationItem(position); 
     } 

最後一有這樣的結果:link(gif)