如何让更宽的图像在后台滚动

2024-05-26

就像 LinkedIn 中的前三个屏幕一样

  1. Splash
  2. 登录/注册按钮
  3. 登录/注册表单

它们都具有相同的背景图像,但是当我们从一个活动移动到另一个活动时,背景图像从右滚动到左侧。

我只能尝试overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right);但事实并非如此。


这称为视差滚动,我使用 2 层来实现它:一层用于内容,另一层用于背景。 内容,你把它放在没有背景的ViewPager上。请注意,您将使用由 viewpager 进行动画处理的片段(每个页面都将是一个片段),而不是活动。 (参见 FragmentStatePagerAdapter)

背景位于背景层上,显然位于 viewpager 后面并且独立于它。它可以是滚动视图内的图像,也可以是您将移动其剪切区域的图像,或者是通过drawBitmap(x,y) 渲染的图像。请参阅我的解决方案的附加源代码,该解决方案扩展了一个视图,只需调用方法“setPercent”即可滚动其背景

然后你覆盖

viewPager.setOnPageChangeListener(new OnPageChangeListener(){

    @Override
    public void onPageScrolled(int position, float percent, int pixoffset) {

        // this is called while user's flinging with:
        // position is the page number
        // percent is the percentage scrolled (0...1)
        // pixoffset is the pixel offset related to that percentage
        // so we got everything we need ....

        int totalpages=mViewPagerAdapter.getCount(); // the total number of pages
        float finalPercentage=((position+percent)*100/totalpages); // percentage of this page+offset respect the total pages
        setBackgroundX ((int)finalPercentage);
    }
}

void setBackgroundX(int scrollPosition) {
        // now you have to scroll the background layer to this position. You can either adjust the clipping or
        // the background X coordinate, or a scroll position if you use an image inside an scrollview ...
                    // I personally like to extend View and draw a scaled bitmap with a clipping region (drawBitmap with Rect parameters), so just modifying the X position then calling invalidate will do. See attached source ParallaxBackground
          parallaxBackground.setPercent(position);
}

现在是视差背景视图,位于 ViewPager 后面。我在这里发布了我自己的 ParallaxBackgroundView 的完整工作版本。这是经过实际测试的代码。

        package com.regaliz.gui.views;

    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.Bitmap.Config;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Rect;
    import android.graphics.drawable.BitmapDrawable;
    import android.graphics.drawable.Drawable;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.View;

    /**
     * Implements a horizontal parallax background. The image is set via setImageDrawable(), it is then scaled to 150% and 
     * you set the percentage via setPErcentage.
     * @author rodo
     */

    public class ParallaxBackground extends View {

        private final static String TAG="ParallaxBackground";
        private final static int MODE_PRESCALE=0, MODE_POSTSCALE=1;

        /** How much a image will be scaled  */
        /** Warning: A full screen image on a Samsung 10.1 scaled to 1.5 consumes 6Mb !! So be careful */
        private final static float FACTOR=1.5f;

        /** The current background */
        private Bitmap mCurrentBackground=null;

        /** Current progress 0...100 */
        private float mOffsetPercent=0;

        /** Flag to activate */
        private boolean isParallax=true;

        /** The parallax mode (MODE_XXX) */
        private int mParallaxMode=MODE_PRESCALE;

        /** precalc stuff to tighten onDraw calls */
        private int  mCurrentFactorWidth;
        private float mCurrentFactorMultiplier;
        private Rect mRectDestination, mRectSource;

        private Paint mPaint;


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

        public ParallaxBackground(Context context) {
            super(context);
            construct(context);
        }

        /**
         * Enables or disables parallax mode
         * @param status
         */

        public void setParallax(boolean status) {
            Log.d(TAG, "*** PARALLAX: "+status);
            isParallax=status;
        }

        /**
         * Sets the parallax memory mode. MODE_PRESCALE uses more memory but scrolls slightly smoother. MODE_POSTSCALE uses less memory but is more CPU-intensive.
         * @param mode
         */

        public void setParallaxMemoryMode(int mode) {
            mParallaxMode=mode;
            if (mCurrentBackground!=null) {
                mCurrentBackground.recycle();
                mCurrentBackground=null;
            }
        }

        /**
         * Seth the percentage of the parallax scroll. 0 Means totally left, 100 means totally right.
         * @param percentage The perc,
         */

        public void setPercent(float percentage) {
            if (percentage==mOffsetPercent) return;
            if (percentage>100) percentage=100;
            if (percentage<0) percentage=0;
            mOffsetPercent=percentage; 
            invalidate();
        }

        /**
         * Wether PArallax is active or not.
         * @return ditto.
         */

        public boolean isParallax() {
            return isParallax && (mCurrentBackground!=null);
        }

        /**
         * We override setBackgroundDrawable so we can set the background image as usual, like in a normal view.
         * If parallax is active, it will create the scaled bitmap that we use on onDraw(). If parallax is not
         * active, it will divert to super.setBackgroundDrawable() to draw the background normally.
         * If it is called with anything than a BitMapDrawable, it will clear the stored background and call super()
         */

        @Override
        public void setBackgroundDrawable (Drawable d) {

            Log.d(TAG,  "*** Set background has been called !!");

            if ((!isParallax) || (!(d instanceof BitmapDrawable))) {
                Log.d(TAG, "No parallax is active: Setting background normally.");
                if (mCurrentBackground!=null) {
                    mCurrentBackground.recycle(); // arguably here
                    mCurrentBackground=null;
                }
                super.setBackgroundDrawable(d);
                return;
            }

            switch (mParallaxMode) {

            case MODE_POSTSCALE:
                setBackgroundDrawable_postscale(d);
                break;

            case MODE_PRESCALE:
                setBackgroundDrawable_prescale(d);
                break;
            }

        }

        private void setBackgroundDrawable_prescale(Drawable incomingImage) {

            Bitmap original=((BitmapDrawable) incomingImage).getBitmap();
            Log.v(TAG, "Created bitmap for background : original: "+original.getByteCount()+", w="+original.getWidth()+", h="+original.getHeight());

            mCurrentBackground=Bitmap.createBitmap((int) (this.getWidth()*FACTOR), this.getHeight(), Config.ARGB_8888);
            Canvas canvas=new Canvas(mCurrentBackground);

            // we crop the original image up and down, as it has been expanded to FACTOR
            // you can play with the Adjustement value to crop top, center or bottom.
            // I only use center so its hardcoded.

            float scaledBitmapFinalHeight=original.getHeight()*mCurrentBackground.getWidth()/original.getWidth();
            int adjustment=0;

            if (scaledBitmapFinalHeight>mCurrentBackground.getHeight()) {
                // as expected, we have to crop up&down to maintain aspect ratio
                adjustment=(int)(scaledBitmapFinalHeight-mCurrentBackground.getHeight()) / 4;
            } 

            Rect srect=new Rect(0,adjustment,original.getWidth(), original.getHeight()-adjustment);
            Rect drect=new Rect(0,0,mCurrentBackground.getWidth(), mCurrentBackground.getHeight());

            canvas.drawBitmap(original, srect, drect, mPaint);

            Log.v(TAG, "Created bitmap for background : Size: "+mCurrentBackground.getByteCount()+", w="+mCurrentBackground.getWidth()+", h="+mCurrentBackground.getHeight());

            // precalc factor multiplier
            mCurrentFactorMultiplier=(FACTOR-1)*getWidth()/100;

            original.recycle();
            System.gc();

            invalidate();
        }



        private void setBackgroundDrawable_postscale (Drawable d) {

            mCurrentBackground=((BitmapDrawable) d).getBitmap();

            int currentBackgroundWidth=mCurrentBackground.getWidth(),
                currentBackgroundHeight=mCurrentBackground.getHeight(),
                currentFactorHeight=(int) (currentBackgroundHeight/FACTOR);

            mCurrentFactorWidth=(int) (currentBackgroundWidth/FACTOR);
            mCurrentFactorMultiplier=(FACTOR-1)*currentBackgroundWidth/100;
            mRectDestination=new Rect(0,0,getWidth(), getHeight());
            mRectSource=new Rect(0,0,mCurrentFactorWidth,currentFactorHeight);
            invalidate();
        }

        @Override
        public void onDraw(Canvas canvas) {
            if ((isParallax) && (mCurrentBackground!=null)) {
                if (mParallaxMode==MODE_POSTSCALE) onDraw_postscale(canvas); else onDraw_prescale(canvas);
            } else super.onDraw(canvas);
        }

        private void onDraw_prescale(Canvas canvas) {
            int oxb=(int) (mCurrentFactorMultiplier*mOffsetPercent);
            canvas.drawBitmap(mCurrentBackground, -oxb, 0, mPaint);
        }

        private void onDraw_postscale(Canvas canvas) {
            int oxb=(int) (mCurrentFactorMultiplier*mOffsetPercent);
            mRectSource.left=oxb;
            mRectSource.right=mCurrentFactorWidth+oxb;
            canvas.drawBitmap(mCurrentBackground,mRectSource,mRectDestination, mPaint);
        }

        private void construct(Context context) {
            mPaint=new Paint();
        }
    }

    //// EOF ParallaxBackground.java

Note:您可以通过编程方式或在 XML 中实例化 ParallaxBackground。只要确保它位于 viewpager 后面即可。要在 XML 中实例化它,您不需要做特殊的事情:

<com.regaliz.gui.views.ParallaxBackground
    android:id="@+id/masterBackground"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    />

然后您可以像任何其他视图一样使用该组件

ParallaxBackground back=findViewById(R.id.masterBackground);
back.setBackgroundDrawable(R.drawable.your_cool_drawable);

Note 2:如果您使用的是 Jelly Bean API,您将看到 SetBackgroundDrawable(Drawable d) 已被 setBackground(Drawable d) 替代。我还没有使用 JB api,但您所要做的就是将 setBackgroundDrawable 重命名为 setBackground。 ** 这个很重要 **

Note 3:ParallaxBackgroundView 有 2 种模式:MODE_PRESCALE 和 MODE_POSTSCALE。 PRESCALE 模式会缩放位图并将其始终保留在内存中,因此 onDraw 应该更快。 POSTSCALE 模式不进行任何预缩放,而是在 onDraw() 上完成缩放。这相当慢,但它可能适用于无法在内存中保存巨大位图的低内存设备。

希望能帮助到你!

顺便说一句,我总是对优化我的代码感兴趣,所以如果有人有一个很好的建议,特别是与性能或内存相关的建议,或者增强这个类,请发布它!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何让更宽的图像在后台滚动 的相关文章

  • 类型容器“Android 依赖项”引用不存在的库 android-support-v7-appcompat/bin/android-support-v7-appcompat.jar

    我在尝试在我的项目中使用 Action Bar Compat 支持库时遇到了某种错误 我不知道出了什么问题 因为我已按照此链接中的说明进行操作 gt http developer android com tools support libr
  • React Native 从 JavaScript 代码内部访问 strings.xml

    有没有办法访问当前值android app src main res values strings xml从 JavaScript 代码内部 我想为每个构建放置不同的端点 URL 但我什至无法检测到反应本机代码内的构建类型 而不必求助于 D
  • 如何重试已消耗的 Observable?

    我正在尝试重新执行失败的已定义可观察对象 一起使用 Retrofit2 和 RxJava2 我想在单击按钮时重试特定请求及其订阅和行为 那可能吗 service excecuteLoginService url tokenModel Ret
  • android中向sqlite中插入大量数据

    目前 我必须一次向我的 Android 中插入超过 100 亿条数据 然而 内存不足的问题会使程序崩溃 sqlite 插入测试非常简单 只需使用 for 循环生成 sql 插入命令并通过 开始 和 提交 进行包装 private Array
  • 在 ViewPager Fragments 中使用 Master/Detail 模板(下载链接)

    工作代码 https github com lukeallison ViewPagerMasterDetail https github com lukeallison ViewPagerMasterDetail Android 主 详细流
  • Android 30+ 中的视频捕获意图 - 只有所有者才能与待处理项目交互

    我正在尝试在我的应用程序上捕获视频 它可以在 android API 30 以下运行 但不能在 30 以上运行 似乎在 sdk 30 之后 android 不允许完全读取外部存储 作用域存储 我目前遇到这个错误 java lang Ille
  • Adobe 是否为其 PDF 阅读器提供 Android SDK 或 API? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我希望能够在我们的应用程序内的视图中显示本地 PDF 文件 在 Android 4 03 下的平板电脑上运行 目前 我们将 Adob eR
  • 找不到处理意图 com.instagram.share.ADD_TO_STORY 的活动

    在我们的 React Native 应用程序中 我们试图让用户根据视图 组件中的选择直接将特定图像共享到提要或故事 当我们尝试直接使用 com instagram share ADD TO FEED 进行共享时 它以一致的方式完美运行 但是
  • Android SIP 来电使用带有广播接收器的服务

    大家好 其实我正在尝试创建一个应用程序 支持基于 SIP 通过互联网进行音频呼叫 这里使用本机 sip 我遇到了来电问题 我已经完成了服务的注册部分 但是在接听电话时我无法接听电话 请帮助我 Service file package exa
  • 是否必须删除 Intent extra?

    这可能是一个愚蠢的问题 但是是否有一条规则规定消费活动必须显式删除 Intent 额外内容 或者只有在回收 Intent 对象时才如此 换句话说 如果我总是通过执行以下操作来链接到下一个活动 Intent i new Intent MyCu
  • 是否有 ADB 命令来检查媒体是否正在播放

    我想使用 ADB 命令检查根植于终端的外部设备中是否正在播放音频 视频 我无法找到任何 ADB 命令 如果有 我尝试过 adb shell dumpsys media player 我想要一个命令来指定视频是否正在运行 您可以使用以下命令查
  • 在gradle插件中获取应用程序变体的包名称

    我正在构建一个 gradle 插件 为每个应用程序变体添加一个新任务 此新任务需要应用程序变体的包名称 这是我当前的代码 它停止使用最新版本的 android gradle 插件 private String getPackageName
  • JavaMail 只获取新邮件

    我想知道是否有一种方法可以在javamail中只获取新消息 例如 在初始加载时 获取收件箱中的所有消息并存储它们 然后 每当应用程序再次加载时 仅获取新消息 而不是再次重新加载它们 javamail 可以做到这一点吗 它是如何工作的 一些背
  • 你的CPU不支持NX

    我刚刚下载了 android studio 但是我遇到了一个问题 当我运行它时 它说你的 cpu 不支持 NX 我应该怎么办 NX 或实际上是 NX 处理器位 是处理器的一项功能 有助于保护您的 PC 免受恶意软件的攻击 当此功能未启用并且
  • Google 云端硬盘身份验证异常 - 需要许可吗? (v2)

    我一直在尝试将 Google Drive v2 添加到我的 Android 应用程序中 但无法获得授权 我收到 UserRecoverableAuthIOException 并显示消息 NeedPermission 我感觉 Google A
  • 在两个活动之间传输数据[重复]

    这个问题在这里已经有答案了 我正在尝试在两个不同的活动之间发送和接收数据 我在这个网站上看到了一些其他问题 但没有任何问题涉及保留头等舱的状态 例如 如果我想从 A 类发送一个整数 X 到 B 类 然后对整数 X 进行一些操作 然后将其发送
  • .isProviderEnabled(LocationManager.NETWORK_PROVIDER) 在 Android 中始终为 true

    我不知道为什么 但我的变量isNetowrkEnabled总是返回 true 我的设备上是否启用互联网并不重要 这是我的GPSTracker class public class GPSTracker extends Service imp
  • 如何根据 gradle 风格设置变量

    我想传递一个变量test我为每种风格设置了不同的值作为 NDK 的定义 但出于某种原因 他总是忽略了最后味道的价值 这是 build gradle apply plugin com android library def test andr
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • Crashlytics 出现 Android Studio 构建错误

    我正在尝试将 CrashLytics 与 Android Studio 和 gradle 一起使用 但出现一个令人困惑的错误 java lang NoSuchMethodError 我的 build gradle 是 buildscript

随机推荐

  • 如何在方法模板中使用模板类型的引用传递参数?

    我目前正在努力编译以下代码 首先是包含带有方法模板的类的头文件 ConfigurationContext h class ConfigurationContext public template
  • 起订量工作单元

    我是单元测试的新手 我想为我的搜索功能创建一个测试 我的服务层看起来像 public class EmployeeService BaseService IEmployeeService public EmployeeService IUn
  • 获取不带波形符的泛型类名称[重复]

    这个问题在这里已经有答案了 我正在尝试获取类型名称T使用这个 typeof T Name 班级名称是ConfigSettings 而不是返回ConfigSettings它正在返回ConfigSettings 1 有什么具体原因吗 我怎样才能
  • 如何修复 TcpClient Ip 标头错误校验和

    我正在使用 System Net Sockets TcpClient 类 但每当我通过网络发送自定义数据包时 我都会在wireshark捕获上看到错误的校验和 我该如何修复它 问题是您在网络接口上设置了校验和卸载 这会导致您的网卡计算校验和
  • 如何获取 PropertyGrid 的单元格值 (c#)?

    如何在 C 中获取属性网格项和项的值 例如 Name Ali LastName Ahmadi Name 和 LastName 是 propertygrid 的 2 个属性 PropertyGrid只是对象的组件模型表示的视图 我会说 查看组
  • 无法转换“String!”类型的值预期参数类型错误

    我有一个公共职能 public func lastActivityFor userName String gt String 后来我想将其称为 OneLastActivity lastActivityFor username 但最后一行出现
  • 错误:找不到符号 ArrayList

    我正在尝试创建某种列表来存储数组 表 中的值 我在这里使用数组列表 但我应该使用列表吗 但是 每次我尝试编译时 它都会引发以下错误 找不到标志 符号 ArrayList类 位置 玩家类 TablePlayer 代码如下 public cla
  • FPC:RTTI 记录

    这是我第一次访问这个网站 通常 我可以毫无问题地在旧帖子中找到回复 但我无法成功解决我的实际问题 我想知道如何使用 RTTI 函数在运行时了解 Lazarus FPC 下记录的属性 成员 我知道如何为类 Tpersistent 后代和已发布
  • 序列化 Django Rest 框架时的附加字段

    我是 django 休息框架的新手 并创建了一个示例Employee model My 模型 py class Employees models Model created models DateTimeField auto now add
  • Ruby,通过 SSH 和 LOG 逐一运行 linux 命令

    我想用 Ruby 女巫 net ssh 编写代码 在远程 Linux 机器上一一运行命令并记录所有内容 在 Linux 机器上称为命令 stdout 和 stderr 所以我写函数 def rs ssh cmds cmds each do
  • 使用 pywin32com 进行 opc 的内存泄漏

    我很难弄清楚如何解决内存泄漏问题 我认为这可能是 pywin32 的问题 但我不完全确定 我用于读取 写入单个项目的代码似乎工作得很好 但是当使用组函数时 它会慢慢泄漏内存 我怀疑这是来自必须在 server handles 中传递的基于
  • Node Js - 识别请求是来自移动设备还是非移动设备

    我对 Node js 还是个新手 是否有任何解决方法或方法如何使用 Node js 识别来自客户端的请求是来自移动设备还是非移动设备 因为我现在正在做的是我想根据设备类型 移动 桌面 限制对某些 API 的访问 我在服务器端使用restif
  • 如何使用networkx删除有向图中的所有相关节点?

    我不确定我的问题的正确术语是什么 所以我只会解释我想做的事情 我有一个有向图 删除节点后我希望所有独立相关的节点也被删除 这是一个例子 假设我删除节点 11 我希望节点 2 也被删除 在我自己的示例中 它们将是 2 以下的节点 现在也必须删
  • html div位置和显示

    Hi 我正在尝试设计一个网站 使用 5 个不同的 div 如上所示 A 是标题 背景图像 重复 x B 是导航栏 1 div 内的图像 应具有 100 高度 C 是内容面板 div 应该是页面滚动期间唯一移动的部分 D 是页脚 div 应始
  • Java 堆分析因 SIGABRT 崩溃

    我正在尝试分析由 C 编写的方法分配并插入的本机内存JVM通过JNI 我安装了 valgrind version valgrind 3 13 0 并尝试使用以下选项运行 JVM valgrind tool massif massif out
  • 用于轻松动态反射的 C# 库

    是否有任何库 例如开源项目等 可以更轻松地使用复杂的反射 例如动态创建对象或类 检查实例等 Thanks 有一个LinFu http www codeproject com KB cs LinFuPart1 aspx可用的库除了反射之外还可
  • 树莓派上的 /dev/mem 访问被拒绝

    我正在使用我的 Raspberry Pi 并且正在编写一个 cgi python 脚本 该脚本创建一个网页来控制我的 gpio 输出引脚 当我尝试将 RPi GPIO 作为 GPIO 导入时 我的脚本崩溃了 这是我收到的错误 File co
  • 使用 div 标签定位元素

    div class HeaderLink div class HeadPanelElement a href Blog a div div
  • 谷歌地图上太多图钉的最佳解决方案

    这是我的 Google 地图 设置 我从数据库中读取了所有标记的位置 低于 300 将它们作为 Json 发送到 javascript 在 javascript 上 我解析 json 查看标记数组并创建一个新的 google maps Ma
  • 如何让更宽的图像在后台滚动

    就像 LinkedIn 中的前三个屏幕一样 Splash 登录 注册按钮 登录 注册表单 它们都具有相同的背景图像 但是当我们从一个活动移动到另一个活动时 背景图像从右滚动到左侧 我只能尝试overridePendingTransition