Параллакс изображения при прокрутке

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

Пример реализации можно найти в приложении Airbnb. Когда вы прокручиваете вниз, вы можете видеть больше изображения внизу, и при прокрутке вверх вы можете видеть больше изображения сверху.

Любые подсказки и советы о том, как создать такой эффект?

enter image description hereenter image description here

Ответ 1

Есть несколько библиотек, которые влияют на эффект параллакса, это зависит от вашего приложения, если оно полезно для вашего конкретного случая, например:

Google - ваш друг-друг;), если ни одно из них не соответствует вашим потребностям, вам нужно создать пользовательский ScrollView, но это более длинный рассказ, сначала попробуйте и опубликуйте свои результаты.

Изменить

Если ни один из этих вариантов не соответствует вашим требованиям, это то, что вам нужно сделать:

Сначала создайте пользовательский ScrollView, чтобы вы могли прослушивать изменения прокрутки.

public class ObservableScrollView extends ScrollView {

    public interface OnScrollChangedListener {
        public void onScrollChanged(int deltaX, int deltaY);
    }

    private OnScrollChangedListener mOnScrollChangedListener;

    public ObservableScrollView(Context context) {
        super(context);
    }

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

    public ObservableScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if(mOnScrollChangedListener != null) {
            mOnScrollChangedListener.onScrollChanged(l - oldl, t - oldt);
        }
    }

    public void setOnScrollChangedListener(OnScrollChangedListener listener) {
        mOnScrollChangedListener = listener;
    }
}

Очевидно, вам нужно использовать это в своем макете вместо стандартного ScrollView:

<your.app.package.ObservableScrollView
        android:id="@+id/scroll_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

Также вам нужно обернуть свой ImageView внутри контейнера, чтобы заставить параллакс работать:

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

    <ImageView
        android:id="@+id/img"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop" />
</FrameLayout>

Наконец, установите Activity в качестве слушателя для вашего нового ObservableScrollView и начните параллакс:

public class MyActivity extends Activity implements ObservableScrollView.OnScrollChangedListener {
    private ObservableScrollView mScrollView;
    private View imgContainer;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        // Init your layout and set your listener
        mScrollView = (ObservableScrollView)findViewById(R.id.scroll_view);
        mScrollView.setOnScrollChangedListener(this);
        // Store the reference of your image container
        imgContainer = findViewById(R.id.img_container);
    }

     @Override
    public void onScrollChanged(int deltaX, int deltaY) {
        int scrollY = mScrollView.getScrollY();
        // Add parallax effect
        imgContainer.setTranslationY(scrollY * 0.5f);
    }
}

Вы можете изменить значение 0,5 в зависимости от того, сколько параллакса вы хотите.

Изменить

Вышеупомянутый ответ работает отлично, если ваш ImageView находится в верхней части действия. Я добавляю код ниже, чтобы добавить функциональность, чтобы иметь ImageView в любом месте макета активности, который я успешно сделал для работы. Это общие вычисления (возможно, некоторые ошибки), и с небольшой настройкой вы можете заставить его работать для вашего собственного дела.

В этом примере у меня есть высота исправления для контейнера 200dp изображения и для изображения 240dp. Основная цель заключается в том, когда контейнер изображения находится в середине экрана, не имеет эффекта параллакса, и когда пользователь прокручивает вверх или вниз, чтобы применить эффект. Так как контейнер изображения приближается к верхней части экрана или ближе к нижней части экрана, будет применяться эффект параллакса. Следующие вычисления немного трудно понять, читая их, поэтому постарайтесь сделать пример с реальными числами на бумаге.

public class MyActivity extends Activity implements ObservableScrollView.OnScrollChangedListener {
    private ObservableScrollView mScrollView;
    private View imgContainer;
    private ImageView mImageView;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        // Init your layout and set your listener
        mScrollView = (ObservableScrollView)findViewById(R.id.scroll_view);
        mScrollView.setOnScrollChangedListener(this);
        // Store the reference of your image container
        imgContainer = findViewById(R.id.img_container);
        // Store the reference of your image
        mImageView =  findViewById(R.id.img);
    }

     @Override
    public void onScrollChanged(int deltaX, int deltaY) {
        // Get scroll view screen bound
        Rect scrollBounds = new Rect();
        mScrollView.getHitRect(scrollBounds);

        // Check if image container is visible in the screen
        // so to apply the translation only when the container is visible to the user
        if (imgContainer.getLocalVisibleRect(scrollBounds)) {
            Display display = getWindowManager().getDefaultDisplay();
            DisplayMetrics outMetrics = new DisplayMetrics ();
            display.getMetrics(outMetrics);
            // Get screen density
            float density  = getResources().getDisplayMetrics().density;

            // Get screen height in pixels            
            float dpHeight = outMetrics.heightPixels / density;
            int screen_height_pixels = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpHeight, getResources().getDisplayMetrics());
            int half_screen_height = screen_height_pixels/2;

            // Get image container height in pixels
            int container_height_pixels = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200, getResources().getDisplayMetrics());

            // Get the location that consider a vertical center for the image (where the translation should be zero)
            int center = half_screen_height - (container_height_pixels/2);

            // get the location (x,y) of the image container in pixels
            int[] loc_screen = {0,0};
            imgContainer.getLocationOnScreen(loc_screen);

            // trying to transform the current image container location into percentage
            // so when the image container is exaclty in the middle of the screen percentage should be zero
            // and as the image container getting closer to the edges of the screen should increase to 100%
            int final_loc = ((loc_screen[1]-center)*100)/half_screen_height;

            // translate the inner image taking consideration also the density of the screen
            mImageView.setTranslationY(-final_loc * 0.4f * density);
        }
    }
}

Я надеюсь, что это поможет кому-то, кто ищет аналогичную функциональность.

Ответ 2

   scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {
            int top = scrollView.getScrollY(); // Increases when scrolling up ^
            if(top != 0) {
                int newTop = (int) (top * .5f);
                imageFrame.setTop(newTop < 0 ? 0 : newTop);
            }
        }
    });

Ответ 3

введите описание изображения здесь

@Override
     public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,int totalItemCount)                                                                                             
              {
                if (listView.getFirstVisiblePosition() == 0) {
                View firstChild = listView.getChildAt(0);
                int topY = 0;
                if (firstChild != null) {
                    topY = firstChild.getTop();
                }

                int heroTopY = stickyViewSpacer.getTop();
                stickyView.setY(Math.max(0, heroTopY + topY));
                imageView.setY(topY * 0.5f);
            }
        }
    });

для получения дополнительной справки нажмите здесь http://androiddhina.blogspot.in/2015/08/listview-header-parallax-with-sticky-view-in-android.html