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

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

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

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

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

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

  • ParallaxScroll
  • Paralloid

Google – ваш друг-друг;) если ни одно из них не соответствует вашим потребностям, вам нужно создать собственный ScrollView но это более длинная история, сначала попробуйте и 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); } } } 

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

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

 @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

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