2013-06-20 13 views
11

jak w LinkedIn pierwsze trzy ekranyJak mieć szerszy obraz przewijanie w tle

  1. Splash
  2. Logowanie/Rejestracja Przyciski
  3. Logowanie/Formularz zgłoszeniowy

wszystkie mają ten sam obraz co tło, ale gdy przechodzimy z jednej czynności do drugiej, obraz tła przewija się w lewo od dobrze.

Mogłem tylko próbować z overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right); Ale to nie jest to, jak to wygląda.

enter image description here

enter image description here

enter image description here

+0

Chcesz animacji suwaka od lewej do prawej? – jigar

Odpowiedz

25

To się nazywa zwój paralaksy i zaimplementowałem go za pomocą 2 warstw: jednej dla treści i drugiej dla tła. Zawartość umieszczasz na ViewPager bez tła. Zwróć uwagę, że zamiast działań będziesz używał Fragmentów (każda strona będzie fragmentem), które będą animowane przez widok strony. (Zobacz FragmentStatePagerAdapter)

Tło jest na warstwie tła, oczywiście za viewpager i niezależnie od niego. Może to być obraz wewnątrz przewijania lub obraz, którego obszar obcinania będzie się poruszał, lub obraz, który renderujesz za pomocą drawBitmap (x, y). Proszę patrz załączony źródło dla mojego rozwiązania, które rozciąga się widok, którego tło może być przewijane tylko wywołanie metody „setPercent”

Następnie należy zastąpić

viewPager.setOnPageChangeListener(new OnPageChangeListener(){ 

    @Override 
    public void onPageScrolled(int position, float percent, int pixoffset) { 

     // this is called while user's flinging with: 
     // position is the page number 
     // percent is the percentage scrolled (0...1) 
     // pixoffset is the pixel offset related to that percentage 
     // so we got everything we need .... 

     int totalpages=mViewPagerAdapter.getCount(); // the total number of pages 
     float finalPercentage=((position+percent)*100/totalpages); // percentage of this page+offset respect the total pages 
     setBackgroundX ((int)finalPercentage); 
    } 
} 

void setBackgroundX(int scrollPosition) { 
     // now you have to scroll the background layer to this position. You can either adjust the clipping or 
     // the background X coordinate, or a scroll position if you use an image inside an scrollview ... 
        // I personally like to extend View and draw a scaled bitmap with a clipping region (drawBitmap with Rect parameters), so just modifying the X position then calling invalidate will do. See attached source ParallaxBackground 
      parallaxBackground.setPercent(position); 
} 

A teraz Syndykat zbrodni tło, które idzie za ViewPager . Zamieszczam tutaj pełną, działającą wersję mojego ParallaxBackgroundView. To jest faktycznie testowany kod.

 package com.regaliz.gui.views; 

    import android.content.Context; 
    import android.graphics.Bitmap; 
    import android.graphics.Bitmap.Config; 
    import android.graphics.Canvas; 
    import android.graphics.Paint; 
    import android.graphics.Rect; 
    import android.graphics.drawable.BitmapDrawable; 
    import android.graphics.drawable.Drawable; 
    import android.util.AttributeSet; 
    import android.util.Log; 
    import android.view.View; 

    /** 
    * Implements a horizontal parallax background. The image is set via setImageDrawable(), it is then scaled to 150% and 
    * you set the percentage via setPErcentage. 
    * @author rodo 
    */ 

    public class ParallaxBackground extends View { 

     private final static String TAG="ParallaxBackground"; 
     private final static int MODE_PRESCALE=0, MODE_POSTSCALE=1; 

     /** How much a image will be scaled */ 
     /** Warning: A full screen image on a Samsung 10.1 scaled to 1.5 consumes 6Mb !! So be careful */ 
     private final static float FACTOR=1.5f; 

     /** The current background */ 
     private Bitmap mCurrentBackground=null; 

     /** Current progress 0...100 */ 
     private float mOffsetPercent=0; 

     /** Flag to activate */ 
     private boolean isParallax=true; 

     /** The parallax mode (MODE_XXX) */ 
     private int mParallaxMode=MODE_PRESCALE; 

     /** precalc stuff to tighten onDraw calls */ 
     private int mCurrentFactorWidth; 
     private float mCurrentFactorMultiplier; 
     private Rect mRectDestination, mRectSource; 

     private Paint mPaint; 


     public ParallaxBackground(Context context, AttributeSet attrs) { 
      super(context, attrs); 
      construct(context); 
     } 

     public ParallaxBackground(Context context) { 
      super(context); 
      construct(context); 
     } 

     /** 
     * Enables or disables parallax mode 
     * @param status 
     */ 

     public void setParallax(boolean status) { 
      Log.d(TAG, "*** PARALLAX: "+status); 
      isParallax=status; 
     } 

     /** 
     * Sets the parallax memory mode. MODE_PRESCALE uses more memory but scrolls slightly smoother. MODE_POSTSCALE uses less memory but is more CPU-intensive. 
     * @param mode 
     */ 

     public void setParallaxMemoryMode(int mode) { 
      mParallaxMode=mode; 
      if (mCurrentBackground!=null) { 
       mCurrentBackground.recycle(); 
       mCurrentBackground=null; 
      } 
     } 

     /** 
     * Seth the percentage of the parallax scroll. 0 Means totally left, 100 means totally right. 
     * @param percentage The perc, 
     */ 

     public void setPercent(float percentage) { 
      if (percentage==mOffsetPercent) return; 
      if (percentage>100) percentage=100; 
      if (percentage<0) percentage=0; 
      mOffsetPercent=percentage; 
      invalidate(); 
     } 

     /** 
     * Wether PArallax is active or not. 
     * @return ditto. 
     */ 

     public boolean isParallax() { 
      return isParallax && (mCurrentBackground!=null); 
     } 

     /** 
     * We override setBackgroundDrawable so we can set the background image as usual, like in a normal view. 
     * If parallax is active, it will create the scaled bitmap that we use on onDraw(). If parallax is not 
     * active, it will divert to super.setBackgroundDrawable() to draw the background normally. 
     * If it is called with anything than a BitMapDrawable, it will clear the stored background and call super() 
     */ 

     @Override 
     public void setBackgroundDrawable (Drawable d) { 

      Log.d(TAG, "*** Set background has been called !!"); 

      if ((!isParallax) || (!(d instanceof BitmapDrawable))) { 
       Log.d(TAG, "No parallax is active: Setting background normally."); 
       if (mCurrentBackground!=null) { 
        mCurrentBackground.recycle(); // arguably here 
        mCurrentBackground=null; 
       } 
       super.setBackgroundDrawable(d); 
       return; 
      } 

      switch (mParallaxMode) { 

      case MODE_POSTSCALE: 
       setBackgroundDrawable_postscale(d); 
       break; 

      case MODE_PRESCALE: 
       setBackgroundDrawable_prescale(d); 
       break; 
      } 

     } 

     private void setBackgroundDrawable_prescale(Drawable incomingImage) { 

      Bitmap original=((BitmapDrawable) incomingImage).getBitmap(); 
      Log.v(TAG, "Created bitmap for background : original: "+original.getByteCount()+", w="+original.getWidth()+", h="+original.getHeight()); 

      mCurrentBackground=Bitmap.createBitmap((int) (this.getWidth()*FACTOR), this.getHeight(), Config.ARGB_8888); 
      Canvas canvas=new Canvas(mCurrentBackground); 

      // we crop the original image up and down, as it has been expanded to FACTOR 
      // you can play with the Adjustement value to crop top, center or bottom. 
      // I only use center so its hardcoded. 

      float scaledBitmapFinalHeight=original.getHeight()*mCurrentBackground.getWidth()/original.getWidth(); 
      int adjustment=0; 

      if (scaledBitmapFinalHeight>mCurrentBackground.getHeight()) { 
       // as expected, we have to crop up&down to maintain aspect ratio 
       adjustment=(int)(scaledBitmapFinalHeight-mCurrentBackground.getHeight())/4; 
      } 

      Rect srect=new Rect(0,adjustment,original.getWidth(), original.getHeight()-adjustment); 
      Rect drect=new Rect(0,0,mCurrentBackground.getWidth(), mCurrentBackground.getHeight()); 

      canvas.drawBitmap(original, srect, drect, mPaint); 

      Log.v(TAG, "Created bitmap for background : Size: "+mCurrentBackground.getByteCount()+", w="+mCurrentBackground.getWidth()+", h="+mCurrentBackground.getHeight()); 

      // precalc factor multiplier 
      mCurrentFactorMultiplier=(FACTOR-1)*getWidth()/100; 

      original.recycle(); 
      System.gc(); 

      invalidate(); 
     } 



     private void setBackgroundDrawable_postscale (Drawable d) { 

      mCurrentBackground=((BitmapDrawable) d).getBitmap(); 

      int currentBackgroundWidth=mCurrentBackground.getWidth(), 
       currentBackgroundHeight=mCurrentBackground.getHeight(), 
       currentFactorHeight=(int) (currentBackgroundHeight/FACTOR); 

      mCurrentFactorWidth=(int) (currentBackgroundWidth/FACTOR); 
      mCurrentFactorMultiplier=(FACTOR-1)*currentBackgroundWidth/100; 
      mRectDestination=new Rect(0,0,getWidth(), getHeight()); 
      mRectSource=new Rect(0,0,mCurrentFactorWidth,currentFactorHeight); 
      invalidate(); 
     } 

     @Override 
     public void onDraw(Canvas canvas) { 
      if ((isParallax) && (mCurrentBackground!=null)) { 
       if (mParallaxMode==MODE_POSTSCALE) onDraw_postscale(canvas); else onDraw_prescale(canvas); 
      } else super.onDraw(canvas); 
     } 

     private void onDraw_prescale(Canvas canvas) { 
      int oxb=(int) (mCurrentFactorMultiplier*mOffsetPercent); 
      canvas.drawBitmap(mCurrentBackground, -oxb, 0, mPaint); 
     } 

     private void onDraw_postscale(Canvas canvas) { 
      int oxb=(int) (mCurrentFactorMultiplier*mOffsetPercent); 
      mRectSource.left=oxb; 
      mRectSource.right=mCurrentFactorWidth+oxb; 
      canvas.drawBitmap(mCurrentBackground,mRectSource,mRectDestination, mPaint); 
     } 

     private void construct(Context context) { 
      mPaint=new Paint(); 
     } 
    } 

    //// EOF ParallaxBackground.java 

Uwaga: Można instancję ParallaxBackground albo programowo lub w formacie XML. Upewnij się, że znajduje się ona za przeglądarką. Do instancji go w formacie XML nie trzeba robić specjalne rzeczy:

<com.regaliz.gui.views.ParallaxBackground 
    android:id="@+id/masterBackground" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    /> 

Następnie można użyć komponentu tak jak każdy inny widok

ParallaxBackground back=findViewById(R.id.masterBackground); 
back.setBackgroundDrawable(R.drawable.your_cool_drawable); 

UWAGA 2: Jeśli używasz Jelly Bean API, zobaczysz, że SetBackgroundDrawable (Drawable d) został zastąpiony przez setBackground (Drawable d). Nie używam JB api jak dotąd, ale wszystko co musisz zrobić, to zmienić nazwę setBackgroundDrawable na setBackground.** Jest to ważne **

Uwaga 3: ParallaxBackgroundView ma 2 tryby: MODE_PRESCALE i MODE_POSTSCALE. Tryb PRESCALE skaluje bitmapę i utrzymuje ją zawsze w pamięci, dzięki czemu onDraw powinien być szybszy. Tryb POSTSCALE nie wykonuje żadnego prescaling, zamiast tego skalowanie odbywa się na onDraw(). Jest to dość powolne, ale może być przydatne dla urządzeń o niskiej pamięci, których nie stać na przechowywanie ogromnej bitmapy w pamięci.

Mam nadzieję, że pomoże!

Nawiasem mówiąc, zawsze jestem zainteresowany optymalizacją kodu, więc jeśli ktoś ma świetną sugestię, szczególnie wydajność lub pamięć, lub wzmacnia tę klasę, proszę to opublikować !!!

+0

Jeśli używam przeglądarki widoku, nie mogę dodać ich do backstack .. zachowanie przycisku Wstecz, a także przejścia fragmentu. Nie ma mowy, abym mógł korzystać z zajęć tutaj? – user1537779

+0

Czy możliwe jest użycie framelaout i zastąpienie fragmentów? co może rozwiązać mój problem z backstackiem. – user1537779

+0

Działania mają zawsze swoje własne tło, nie można używać tła, a następnie działań na wierzchu. FrameLayout + Zamienniki fragmentów? pewnie! Można również użyć ViewFlipper bez fragmentów. Rzeczą w ViewPager + Fragments jest to, że bardzo ułatwia projektowanie/dodawanie kolejnych fragmentów/etc ... plus możesz wstawiać piękne przejścia między stronami itp. ... na komponencie wypróbowanym i przetestowanym przez Google. Oczywiście zawsze możesz to zrobić samodzielnie. BTW- Możesz również uchwycić klawisz WSTECZ i obsługiwać go samodzielnie. Gdybym był tobą, spróbowałbym tego podczas korzystania z ViewPager, jest to piękny komponent. – rupps

7

Jednym ze sposobów, aby to zrobić jest rozszerzenie ViewPager. To już zostało zrobione przez kogoś i możesz sprawdzić kod na github.

+0

Zgadzam się, to jest niesamowity komponent! –

+0

Działa to świetnie! –

Powiązane problemy