Android 图像滚动时查看视差

Android 图像滚动时查看视差,android,Android,我在滚动或listview视差时看到了许多演示视差背景的示例,但我找不到一个清晰的示例,说明如何在活动中滚动时在图像上实现视差效果 示例实现可在Airbnb应用程序中找到。当你向下滚动时,你可以看到更多的图像底部,当你向上滚动时,你可以看到更多的图像顶部 关于如何创造这样的效果有什么提示和提示吗 有几个库可以产生视差效果,这取决于您的应用程序是否对您的特定情况有用,例如: 谷歌是你的好友;)如果这些都不适合您的需要,那么您必须创建一个自定义的滚动视图,但这是一个较长的故事,请首先尝试一

我在滚动或listview视差时看到了许多演示视差背景的示例,但我找不到一个清晰的示例,说明如何在活动中滚动时在图像上实现视差效果

示例实现可在Airbnb应用程序中找到。当你向下滚动时,你可以看到更多的图像底部,当你向上滚动时,你可以看到更多的图像顶部

关于如何创造这样的效果有什么提示和提示吗


有几个库可以产生视差效果,这取决于您的应用程序是否对您的特定情况有用,例如:

谷歌是你的好友;)如果这些都不适合您的需要,那么您必须创建一个自定义的
滚动视图
,但这是一个较长的故事,请首先尝试一下并发布您的结果

编辑 如果这些都不符合您的要求,则您必须这样做:

首先,创建一个自定义的
滚动视图
,以便您可以收听滚动更改

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">
根据需要的视差大小,可以修改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);
        }
    }
}
我希望它能帮助那些正在寻找类似功能的人。

scrollView.getViewTreeObserver().addOnScrollChangedListener(新的ViewTreeObserver.OnScrollChangedListener(){
   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);
            }
        }
    });
@凌驾 public void onScrollChanged(){ int top=scrollView.getScrollY();//向上滚动时增加^ 如果(顶部!=0){ int newTop=(int)(顶部*.5f); imageFrame.setTop(newTop<0?0:newTop); } } });
似乎提供了很多。谢谢你的回答。我已经看到了它们,但是因为我看不清楚我正在寻找的功能,我决定问一下,以防我错过了一个库!但是你说得对,我必须花时间先试试。@xinaris,它有用吗?如果有,请接受我的帖子作为回答:)谢谢你的努力帮助我!实际上,我有一个类似的代码,用于为活动顶部的图像创建视差效果,效果很好。我的问题实际上是对scrollview中任何位置的imageview产生视差效果。您的代码不适用于此,但您的指导原则很好。该解决方案与您的代码类似,但需要进行一些数学计算,以计算imageview在scrollview中的当前位置。我在@peguerosdc anwser中添加了一些代码,以获得我要求的功能。谢谢你花时间在这上面。@xinaris我已经接受了你的编辑。我很高兴看到我的代码很有用。这使得快速移动时
ImageView
顶部出现间隙。移除
top!=0
检查将修复快速滚动时顶部显示的间隙。删除顶部!=0,但在快速移动时仍会在ImageView顶部留下间隙。还有其他解决办法吗?
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);
        }
    }
}
   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);
            }
        }
    });