草庐IT

android - 滚动时的 Imageview 视差

coder 2023-11-18 原文

我看到很多例子说明视差背景当你滚动或 ListView 视差但是我找不到一个清楚的例子如何在你滚动 Activity 时对图像实现视差效果。

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

关于如何创建这种效果有什么提示和技巧吗?

最佳答案

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

Google 是您的好 friend ;) 如果这些都不符合您的需求,那么您必须创建一个自定义的 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 位于 Activity 的顶部,则上述答案可以正常工作。我在下面发布了一些代码来添加功能,使 ImageView 在我成功工作的 Activity 布局中的任何位置。这些是通用计算(可能有一些错误),稍作调整就可以让它适用于您自己的情况。

对于这个例子,我有一个固定高度的图像容器 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);
        }
    }
}

我希望它可以帮助正在寻找类似功能的人。

关于android - 滚动时的 Imageview 视差,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26990195/

有关android - 滚动时的 Imageview 视差的更多相关文章

  1. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  2. ruby-on-rails - 如何从过时的 TZInfo 标识符中获取 Rails TimeZone 名称? - 2

    已经有一个问题回答了如何将“America/Los_Angeles”转换为“PacificTime(US&Canada)”。但是我想将“美国/太平洋”和其他过时的时区转换为RailsTimeZone。我无法在图书馆中找到任何可以帮助我完成此任务的东西。 最佳答案 来自RailsActiveSupport::TimeZonedocs:TheversionofTZInfobundledwithActiveSupportonlyincludesthedefinitionsnecessarytosupportthezonesdefinedb

  3. ruby - 比较 rspec 中的 float 时的奇怪行为 - 2

    以下测试中的第3个失败:specify{(0.6*2).shouldeql(1.2)}specify{(0.3*3).shouldeql(0.3*3)}specify{(0.3*3).shouldeql(0.9)}#thisonefails这是为什么呢?这是浮点问题还是ruby​​或rspec问题? 最佳答案 从rspec-2.1开始specify{(0.6*2).shouldbe_within(0.01).of(1.2)}在那之前:specify{(0.6*2).shouldbe_close(1.2,0.01)}

  4. ruby - 使用 Nokogiri 替换时的编码问题 - 2

    我有这个代码:#encoding:utf-8require'nokogiri's="CaféVerona".encode('UTF-8')puts"Originalstring:#{s}"@doc=Nokogiri::HTML::DocumentFragment.parse(s)links=@doc.css('a')only_text='CaféVerona'.encode('UTF-8')puts"Replacementtext:#{only_text}"links.first.replace(only_text)puts@doc.to_html但是,输出是这样的:Originals

  5. ruby - 绕过 Element 的方法无法滚动到 View 中 - Watir-webdriver with Ruby - 2

    因此,我们的页面中有以下代码:OnOff这是2个单选按钮。'开和关'。“关闭”是默认值。使用Watir-webdriver和Ruby,我们想要选择“打开”单选按钮。我们这样做:browser.radio(:id=>"HasRegistration_true").set但在这样做时,我们得到以下错误:`WebElement.clickElement':Elementcannotbescrolledintoview:[objectHTMLInputElement](Selenium::WebDriver::Error::MoveTargetOutOfBoundsError)我们知道Sele

  6. Android Studio开发之使用内容组件Content获取通讯信息讲解及实战(附源码 包括添加手机联系人和发短信) - 2

    运行有问题或需要源码请点赞关注收藏后评论区留言一、利用ContentResolver读写联系人在实际开发中,普通App很少会开放数据接口给其他应用访问。内容组件能够派上用场的情况往往是App想要访问系统应用的通讯数据,比如查看联系人,短信,通话记录等等,以及对这些通讯数据及逆行增删改查。首先要给AndroidMaifest.xml中添加响应的权限配置 下面是往手机通讯录添加联系人信息的例子效果如下分成三个步骤先查出联系人的基本信息,然后查询联系人号码,再查询联系人邮箱代码 ContactAddActivity类packagecom.example.chapter07;importandroid

  7. Android 10.0 设置默认launcher后安装另外launcher后默认Launcher失效的功能修复 - 2

    1.前言 在10.0的系统rom定制化开发中,在系统中有多个launcher的时候,会在开机进入launcher的时候弹窗launcher列表,让用户选择进入哪个launcher,这样显得特别的不方便所以产品开发中,要求用RoleManager的相关api来设置默认Launcher,但是在设置完默认Launcher以后,在安装一款Launcher的时候,默认Launcher就会失效,在系统设置的默认应用中Launcher选项就为空,点击home键的时候会弹出默认Launcher列表,让选择进入哪个默认Launcher.所以需要从安装Launcher的流程来分析相关的设置。来解决问题设置默认La

  8. ruby-on-rails - `*` 用作参数时的含义(不像*arg,只是*) - 2

    这个问题在这里已经有了答案:nakedasteriskasparameterinmethoddefinition:deff(*)(1个回答)关闭9年前。当我在阅读Rails代码时,我发现了这个defsave(*)create_or_update||raise(RecordNotSaved)end*有什么作用?:O我知道当我们像*args一样使用它时会发生什么,但在这种情况下,它只是普通的*。引用https://github.com/rails/rails/blob/master/activerecord/lib/active_record/persistence.rb#L119

  9. ruby - 拆分开始和结束时的空字符串 - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:SplitprobleminRuby在Ruby中,当我使用与字符串开头匹配的定界符拆分字符串时,它会在数组的初始位置给出一个空字符串:"abc".split(/a/)#=>["","bc"]但是当我用匹配字符串末尾的分隔符做类似的事情时,它不会给出空字符串:"abc".split(/c/)#=>["ab"]这在我看来不一致。这样的规范有什么理由吗?编辑如果它要与Perl的规范兼容,就像muu中的short答案一样,那么问题仍然是一样的:为什么它在Perl中是这样的?由于这个原因,现在它也变成了一个关于Perl

  10. 出现错误时的 Ruby/Thor 退出状态 - 2

    我是Thor(和Ruby)的新手,我正在考虑在构建脚本中使用它,因为据说它可以替代Rake(从而替代Make)。然而,经过短暂的试用,我对它返回的错误状态感到困惑。我快速浏览了wiki,但没有看到任何提及。只有第一个“简单示例”,test.thor:classTest版本号:eruve>thorversionThor0.18.1我尝试了以下,故意错误的命令:eruve>ruby--version;thortest:examplebadarg;echoexitstatus:$?ruby2.0.0p195(2013-05-14revision40734)[x86_64-darwin10.8

随机推荐