当滚动ImageView的视差视差、ImageView

2023-09-05 08:14:24 作者:烟花再美只是瞬间

我看到很多例子示范视差背景为您滚动或ListView视差,但我无法找到一个明显的例子是如何为您的活动滚动来实现对图像的视差效果。

I saw many examples demonstrative parallax background as you scroll or listview parallax but I cannot find a clear example how to implement a parallax effect on images as you scroll in the activity.

这是示例实现可以发现生活怎样的应用程序被发现。当你向下滚动,你可以看到更多图像的底部,当你向上滚动,你可以看到更多的图像的顶部。

An example implementation can be found in Airbnb app. As you scroll down you can see more of the image's bottom and as you scroll up you can see more of the image's top.

在如何创建这样的效果的任何提示和技巧?

Any hints and tips on how to create such effect?

推荐答案

有几个库,以视差效果,这取决于你的应用程序,如果他们对你的特殊情况下非常有用,例如:

There are a few libraries that to a parallax effect, it depends on your app if they are useful for your particular case, for example:

ParallaxScroll Paralloid ParallaxScroll Paralloid

谷歌是你的朋友,朋友;)如果没有这些适合你的需求,那么你必须创建一个自定义的滚动型但是这是一个较长的故事,首先给他们一个尝试,发表您的结果。

Google is your friend pal ;) if none of these suits your needs then you have to create a custom ScrollView but that's a longer story, first give them a try and post your results.

如果没有这些适合你的requeriments那么这是你必须做的:

If none of these fit your requeriments then this is what you have to do:

首先,创建一个自定义的滚动型这样你就可以听滚动变化。

First, create a custom ScrollView so you can listen to scroll changes.

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

显然,你需要在你的布局使用默认滚动型的这个代替:

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

另外你需要用你的ImageView一个容器内,使视差工作:

Also you need to wrap your ImageView inside a container to make the parallax work:

<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>

最后,设置你的活动作为一个监听器为您的品牌新的 ObservableScrollView ,让视差开始:

Finally set your Activity as a listener for your brand new ObservableScrollView and let the parallax begin:

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的值取决于你有多少的视差想要的。

You can modify the 0.5 value depending on how much parallax you want.

以上回答工作正常,如果你的ImageView是在活动的顶部。我张贴下面的一些code添加的功能在活动中的布局,我成功地在任何地方工作有ImageView的。这是通用计算(可能有一些错误),并用一个小的调整,你可以把它的工作你自己的情况。

The above answer works fine if your ImageView is in the top of the activity. I am posting some code below to add the functionality to have the ImageView anywhere in the activity layout which I successfully made to work. These are generic calculations (might have some mistakes) and with a little tweak you can have it working for your own case.

在这个例子中我有一个固定高度的图像容器200dp和图像240dp。的主要目的是当图像容器处于屏幕中间没有视差效应和作为用户向上或向下滚动以应用效果。所以作为图象容器更接近屏幕的顶部或接近的视差效果越将被应用在屏幕的底部。下面的计算是有点硬通过阅读他们,尽量让在纸上实数的例子就明白了。

For this example I have a fix height for the image container 200dp and for the image 240dp. The main purpose is when the image container is in the middle of the screen have no parallax effect and as the user scroll up or down to apply the effect. So as the image container get closer to the top of the screen or closer to the bottom of the screen the more of the parallax effect will be applied. The following calculations are a little hard to understand by reading them so try to make an example with real numbers in paper.

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

我希望这能帮助别人是正在寻找类似的功能。

I hope it can help someone that is looking for similar functionality.