jjzjj

当我反向运行动画时,Android 会跳过 onDraw()

coder 2023-12-11 原文

我有一个 Sliding Fragments DevByte 的实现.除了将 fragment 滑入 View 之外,我还想在它遮挡的内容上画一个阴影。我已将视频中的 FractionalLinearLayout 修改为 measure 本身,使其位于屏幕宽度的两倍处,并在右半部分 layout 其子元素。在动画循环期间,我在左半部分绘制了一个增加 alpha 的黑色矩形,并将 X 坐标设置为负值以使右半部分可见。

我的问题是,当我将内容滑入 View 时,此方法工作正常,但当我将内容滑出 View 时,此方法失败。在进去的路上,我得到了我想要的行为:平移和变暗的阴影。在出路时,我只得到翻译,阴影在整个动画过程中一直保持它的第一个帧颜色。

我在日志记录中看到的是,在进入过程中,setPercentOnScreen()onDraw() 方法被交替调用,正如预期的那样。然而,在出去的路上,我接到了一个 setPercentageOnScreen() 调用,接着是一个 onDraw() 调用,然后只调用了 setPercentOnScreen()。 Android 正在优化绘图,但我不明白为什么。

更新:有趣的是,我只在运行 Android 4.4 的模拟器上看到这种行为。运行 4.0.3 和 4.3 的模拟器按预期在两个方向运行动画。旧的 Nexus 7 出现问题,不同的模拟器 4.4 没有。它在设备上似乎是一致的,但在设备之间有所不同。

再次更新:我提取了一个示例项目并将其放在 GitHub 上:barend/android-slidingfragment . GitHub 上的自述文件包含十几个设备的测试结果。对于模拟器,问题与“启用主机 GPU”功能相关,但仅在 Jelly Bean 和 KitKat 上;不在 ICS 上。

再次更新:进一步测试表明,问题出现在运行 Jelly Bean 及更高版本的物理设备上,以及运行 Jelly Bean 或更高版本且启用了“使用主机 GPU”的 ARM 模拟器上。无论 Android 版本如何,它都不会出现在没有“使用主机 GPU”的 x86 模拟器和 ARM 模拟器上。我的测试的确切表格可以在上面链接的 github 项目中找到。

// Imports left out
public class HorizontalSlidingLayout extends FrameLayout {
    /**
     * The fraction by which the content has slid into view. Legal range: from 0.0 (all content
     * off-screen) to 1.0 (all content visible).
     */
    private float percentOnScreen;
    private int screenWidth, screenHeight, shift;
    private Paint shadowPaint;

    // Constructors left out, all three call super, then init().

    private void init() {
        if (isInEditMode()) {
            // Ensure content is visible in edit mode.
            percentOnScreen = 1.0f;
        } else {
            setWillNotDraw(false);
            percentOnScreen = 0.0f;
            shadowPaint = new Paint();
            shadowPaint.setAlpha(0x00);
            shadowPaint.setColor(0x000000);
            shadowPaint.setStyle(Paint.Style.FILL);
        }
    }

    /** Reports our own size as (2w, h) and measures all children at (w, h). */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        screenWidth = MeasureSpec.getSize(widthMeasureSpec);
        screenHeight = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(2 * screenWidth, screenHeight);
        for (int i = 0, max = getChildCount(); i < max; i++) {
            View child = getChildAt(i);
            child.measure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    /** Lays out the children in the right half of the view. */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        for (int i = 0, max = getChildCount(); i < max; i++) {
            View child = getChildAt(i);
            child.layout(screenWidth, top, right, bottom);
        }
    }

    /**
     * Draws a translucent shadow in the left half of the view, darkening by
     * {@code percentOnScreen}, then lets superclass draw children in the right half.
     */
    @Override
    protected void onDraw(Canvas canvas) {
        // Maintain 30% translucency
        if (percentOnScreen < 0.7f) {
            shadowPaint.setAlpha((int) (percentOnScreen * 0xFF));
        }
        android.util.Log.i("Slider", "onDraw(" + percentOnScreen + ") -> alpha(" + shadowPaint.getAlpha() + ')');
        canvas.drawRect(shift, 0, screenWidth, screenHeight, shadowPaint);
        super.onDraw(canvas);
    }

    @SuppressWarnings("unused")
    public float getPercentOnScreen() {
        return percentOnScreen;
    }

    /** Repeatedly invoked by an Animator. */
    @SuppressWarnings("unused")
    public void setPercentOnScreen(float fraction) {
        this.percentOnScreen = fraction;
        shift = (int)(fraction < 1.0 ? fraction * screenWidth : screenWidth);
        setX(-shift);
        android.util.Log.i("Slider", "setPOS(" + fraction + ") -> invalidate(" + shift + ',' + screenWidth + ')');
        invalidate(shift, 0, screenWidth, screenHeight);
        //invalidate() // Makes no difference
    }
}

奇怪的是这违反了对称性。我在滑出时和滑入时做的是完全相同的反向操作,但行为不同。我可能忽略了一些愚蠢的事情。有什么想法吗?

最佳答案

这是 Android 中硬件加速 View 的失效/重绘逻辑中的错误。默认情况下,我希望在 JB 中看到相同的错误,但只有在您选择硬件加速时才会在 ICS 上看到(从 JB 开始默认启用 hw accel)。

问题在于,当 View 从层次结构中移除然后动画消失时(例如在您的应用程序的 fragment 事务中发生的情况,或者在移除的 View 淡出时在 LayoutTransition 中发生的情况,或者在淡出 a 的 AlphaAnimation 中发生的情况removed view),它们不参与与普通/父级 subview 相同的失效/重绘逻辑。它们重新显示正确(因此我们看到 fragment 滑出),但它们没有重新绘制,因此如果它们的内容在此期间实际发生变化,它们将不会随这些变化一起重新显示。您的应用程序中错误的影响是 fragment 正确滑出,但未绘制阴影,因为这需要重新绘制 View 以获取这些更改。

您使 View 无效的方式是正确的,但错误意味着无效无效。

这个错误以前没有出现过,因为我相信,消失的 View 在动画消失时改变它们的外观并不常见(它们通常只是滑动或淡出,效果很好)。

该错误应该会在未来的版本中修复(我已经修复了它)。同时,针对您的特定情况的解决方法是也添加父容器的失效;这将强制重绘 View 并正确显示阴影:

if (getParent() instanceof ViewGroup) {
    ((ViewGroup) getParent()).invalidate();
}

关于当我反向运行动画时,Android 会跳过 onDraw(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19742350/

有关当我反向运行动画时,Android 会跳过 onDraw()的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  3. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  4. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  5. ruby - Sinatra:运行 rspec 测试时记录噪音 - 2

    Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/

  6. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  7. ruby-on-rails - 无法让 rspec、spork 和调试器正常运行 - 2

    GivenIamadumbprogrammerandIamusingrspecandIamusingsporkandIwanttodebug...mmm...let'ssaaay,aspecforPhone.那么,我应该把“require'ruby-debug'”行放在哪里,以便在phone_spec.rb的特定点停止处理?(我所要求的只是一个大而粗的箭头,即使是一个有挑战性的程序员也能看到:-3)我已经尝试了很多位置,除非我没有正确测试它们,否则会发生一些奇怪的事情:在spec_helper.rb中的以下位置:require'rubygems'require'spork'

  8. ruby-on-rails - before_filter 运行多个方法 - 2

    是否有可能:before_filter:authenticate_user!||:authenticate_admin! 最佳答案 before_filter:do_authenticationdefdo_authenticationauthenticate_user!||authenticate_admin!end 关于ruby-on-rails-before_filter运行多个方法,我们在StackOverflow上找到一个类似的问题: https://

  9. Vscode+Cmake配置并运行opencv环境(Windows和Ubuntu大同小异) - 2

    之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m

  10. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

随机推荐