2013-06-20 2 views
11

Как в LinkedIn первые три экранаКак иметь более широкое изображение прокрутки в фоновом режиме

  1. Всплеск
  2. Войти/регистрация Кнопки
  3. Войти/Регистрация Форма

все имеют то же изображение, что и фон, но при переходе от одной активности к другой фоновое изображение прокручивается влево от правильно.

Я мог только попробовать overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right); Но это не то, на что это похоже.

enter image description here

enter image description here

enter image description here

+0

, так что вам нужен слайдер, как анимация слева направо? – jigar

ответ

25

Это называется прокруткой параллакса, и я реализовал его, используя 2 слоя: один для контента и еще один для фона. Содержимое, вы размещаете его на ViewPager без фона. Обратите внимание: вместо действий вы будете использовать Фрагменты (каждая страница будет фрагментом), который будет анимироваться с помощью viewpager. (См. FragmentStatePagerAdapter)

Фон находится на фоновом слое, очевидно, за видоискателем и не зависит от него. Это может быть изображение внутри scrollview или изображение, область отсечения которого вы будете перемещать, или изображение, которое вы визуализируете с помощью drawBitmap (x, y). Пожалуйста, прилагается источник для моего решения, который простирается на вид которого фон можно прокручивать только вызов метода «setPercent»

Затем переопределить

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); 
} 

А теперь параллакс вид фона, который выходит за ViewPager , Я размещаю здесь полную рабочую версию своего собственного ParallaxBackgroundView. Это действительно проверенный код.

 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 

Примечание: Вы можете создать экземпляр ParallaxBackground либо программно, либо в XML. Просто убедитесь, что он находится за зрителем. К примеру это в XML вам не нужно делать специальные вещи:

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

Затем вы можете использовать компонент так же, как и любой другой точки зрения

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

Примечание 2: Если вы используете Jelly Bean API, вы увидите, что SetBackgroundDrawable (Drawable d) заменен на setBackground (Drawable d). Я пока не использую JB api, но все, что вам нужно сделать, это переименовать setBackgroundDrawable в setBackground.** Это важно **

Примечание 3: ParallaxBackgroundView имеет 2 режима: MODE_PRESCALE и MODE_POSTSCALE. Режим PRESCALE масштабирует растровое изображение и сохраняет его всегда в памяти, поэтому onDraw должен быть быстрее. Режим POSTSCALE не выполняет никакого предварительного масштабирования, вместо этого масштабирование выполняется на onDraw(). Это довольно медленно, но может быть полезно для устройств с низкой памятью, которые не могут позволить себе хранить огромные растровые изображения в памяти.

Надеюсь, это поможет!

Кстати, я всегда заинтересован в оптимизации моего кода, поэтому, если у кого-то есть большое предложение, особенно производительность или память, или улучшает этот класс, пожалуйста, отправьте его !!!

+0

Если я использую viewpager, я не могу добавить их в backstack..the поведение кнопки кнопки, а также переходы фрагмента. Я не могу использовать здесь действия? – user1537779

+0

Или можно использовать рамку и заменить фрагменты? который может решить мою проблему с backstack. – user1537779

+0

Мероприятия всегда имеют собственный фон, вы не сможете использовать фон, а затем действия сверху. Замена FrameLayout + Fragment? конечно! Вы также можете использовать ViewFlipper без фрагментов. Вещь с ViewPager + Fragments заключается в том, что она очень упрощает разработку/добавление дополнительных фрагментов/etc ... плюс вы можете вставлять красивые переходы страницы и т. Д. На компонент, проверенный и протестированный Google. Конечно, вы всегда можете сделать это самостоятельно. BTW- Вы также можете захватить клавишу BACK и обработать ее самостоятельно. Если бы я был вами, я бы попробовал это при использовании ViewPager, это красивый компонент. – rupps

7

Один из способов сделать это заключается в расширении ViewPager. Это уже сделано кем-то, и вы можете проверить код на github.

+0

Согласен, это замечательный компонент! –

+0

Это отлично работает! –

Смежные вопросы