Android 方向更改时的ImageView-Drawable忽略收进并返回原始状态 编辑3:

Android 方向更改时的ImageView-Drawable忽略收进并返回原始状态 编辑3:,android,screen-orientation,android-imageview,invalidation,android-framelayout,Android,Screen Orientation,Android Imageview,Invalidation,Android Framelayout,出于历史原因,我保留以下原始问题。但是,我发现问题并不是孤立于FrameLayout。因此,更新了标题 我创建了一个示例项目来演示这个问题,而不是用更多的代码来挤满这篇文章;它在谷歌项目托管上 该问题的摘要如下: 可绘制的纵向方向,在其上设置了特定边界,在 更改方向并返回到纵向,不会保留 设定界限。相反,它会恢复到其原始边界。这是在 尽管强制设置了方向变化的明确界限。 请注意,您稍后在单击等时设置的任何边界都将得到遵守 我还有一份报告,其中包含两项单独的活动来说明这一问题 简单的普通活动正好说明

出于历史原因,我保留以下原始问题。但是,我发现问题并不是孤立于
FrameLayout
。因此,更新了标题

我创建了一个示例项目来演示这个问题,而不是用更多的代码来挤满这篇文章;它在谷歌项目托管上

该问题的摘要如下:

可绘制的纵向方向,在其上设置了特定边界,在 更改方向并返回到纵向,不会保留 设定界限。相反,它会恢复到其原始边界。这是在 尽管强制设置了方向变化的明确界限。 请注意,您稍后在单击等时设置的任何边界都将得到遵守

我还有一份报告,其中包含两项单独的活动来说明这一问题

  • 简单的普通活动正好说明了这个问题
  • ImageView
    上使用自定义
    BitmapDrawable
    的活动-此活动在边界更改时打印到日志中
  • 第二个版本清楚地表明,即使我在Drawable上设置了边界,在
    onBoundsChange()
    中也没有遵守这些边界


    原始问题:

    我使用了一个
    FrameLayout
    ,其中两个
    ImageView
    s堆叠在一起,用于显示“电池状态”图形。这是纵向模式。在横向模式下,我显示不同的布局(图表)

    我的问题是,假设电池状态显示为30%。现在,我旋转屏幕并显示图表。当我回到纵向时,电池图形会回到其原始位置(即“满”)

    我尝试了各种各样的方法,试图弄清楚到底发生了什么。调试表明,“顶部”图形的边界确实按照预期设置。所以这似乎是一个无效的问题。我正在介绍2个类和2个布局XML(都是简化的)的代码,这有助于重现问题。同时附加用于ImageView的占位符PNG

    有人能发现错误吗?要重新创建问题,请运行应用程序,然后单击“更新”按钮。图形将“填充”到某个级别。然后,切换到横向,然后返回到纵向。该图形不记得其早期值

    活动:

    public class RotateActivity extends Activity {
    
        private View portraitView, landscapeView;
        private LayoutInflater li;
        private Configuration mConfig;
        private ValueIndicator indicator;
        private Button btn;
        private Random random = new java.util.Random();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            li = LayoutInflater.from(this);
            portraitView = li.inflate(R.layout.portrait, null);
            landscapeView = li.inflate(R.layout.landscape, null);
        }
    
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            mConfig = newConfig;
            initialize();
    
        }
    
        @Override
        protected void onResume() {
            mConfig = getResources().getConfiguration();
            initialize();
            super.onResume();
        }
    
        private void initialize(){
            if(mConfig.orientation == Configuration.ORIENTATION_LANDSCAPE){
                displayLandscape();
            } else {
                displayPortrait();
            }
        }
    
        private void displayLandscape() {
            setContentView(landscapeView);
        }
    
        private void displayPortrait() {
            setContentView(portraitView);
            btn = (Button)portraitView.findViewById(R.id.button1);
            indicator = (ValueIndicator)portraitView.findViewById(R.id.valueIndicator1);
        /*
         * Forcing the graphic to perform redraw to its known state when we return to portrait view.
         */
        indicator.updateIndicatorUi();  
    
    
    
            btn.setOnClickListener(new OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    updateIndicator(random.nextInt(100));
                }
            });
    
        }
    
        private void updateIndicator(int newValue){
            indicator.setPercent(newValue);
        }
    }
    
    trait.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >
    
        <com.gs.kiran.trial.inval.ValueIndicator
                    android:id="@+id/valueIndicator1"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_margin="10dp" />
    
        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Update" />
    
    </LinearLayout>
    
    indicator.xml(自定义视图中使用的FrameLayout的xml)

    
    
    landscape.xml(虚拟占位符-足以重新创建问题)

    
    
    AndroidManifest.xml代码段:

    <activity
                android:label="@string/app_name"
                android:name=".RotateActivity" 
                android:configChanges="orientation|keyboardHidden">
                <intent-filter >
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
    
    

    编辑

    我还尝试调用了
    setPercent()
    ,并在
    displaystraphicview()
    中传递了一个保存的值,这基本上是在我们回到纵向模式时强制更新到已知状态。还是不走运。请注意,日志告诉我可提取项的边界是正确的。我不明白为什么无效判决没有发生


    编辑2:

  • 在ValueIndicator.java中,我引入了一个成员变量
    mPercent
    它始终存储最后一个已知的百分比值
  • 更新了
    setPercent()
    code以更新成员变量
    mPercent
    ;然后调用
    updateIndicateUi()
    方法
  • updateIndicatorUi()
    (现在是一种
    public
    方法)现在使用状态(即
    mPercent
    )来执行其工作
  • 每当我们回到纵向模式时,我调用
    updateIndicatorUi()
    。这将强制电池图形自我更新
  • 我还更新了代码以反映这些更改


    我们的想法是,每当我们从横向模式返回到纵向模式时,强制重新绘制并使其无效。再一次-我确实看到电池“内容”可绘制的界限被设置为所需,但UI拒绝跟上进度。

    只是猜测,但在旋转活动中,请尝试更改超级调用的顺序:

    super.onConfigurationChanged(newConfig); // super called before initialize()
    mConfig = newConfig;
    initialize();
    

    我已经在Google代码宿主上检查了您的代码(感谢您如此彻底地记录代码的努力),我发现当您从横向返回到纵向时,可绘制文件上设置的边界确实再次发生了变化

    绘图表上的边界不是由您的代码更改的,而是由
    ImageView
    的布局方法更改的。放置新布局(
    setContentView
    )时,将运行所有布局代码,包括
    ImageView
    ImageView
    更改其包含的可绘制边界,这就是为什么您将可绘制边界更改为原始边界的原因

    导致绑定更改的堆栈跟踪是:

    Thread [<1> main] (Suspended (entry into method onBoundsChange in BitmapDrawable))  
        BitmapDrawable.onBoundsChange(Rect) line: 293   
        BitmapDrawable(Drawable).setBounds(int, int, int, int) line: 131    
        ImageView.configureBounds() line: 769   
        ImageView.setFrame(int, int, int, int) line: 742    
        ImageView(View).layout(int, int, int, int) line: 7186   
        LinearLayout.setChildFrame(View, int, int, int, int) line: 1254 
        LinearLayout.layoutVertical() line: 1130    
        LinearLayout.onLayout(boolean, int, int, int, int) line: 1047   
        LinearLayout(View).layout(int, int, int, int) line: 7192    
        FrameLayout.onLayout(boolean, int, int, int, int) line: 338 
        FrameLayout(View).layout(int, int, int, int) line: 7192 
        LinearLayout.setChildFrame(View, int, int, int, int) line: 1254 
        LinearLayout.layoutVertical() line: 1130    
        LinearLayout.onLayout(boolean, int, int, int, int) line: 1047   
        LinearLayout(View).layout(int, int, int, int) line: 7192    
        PhoneWindow$DecorView(FrameLayout).onLayout(boolean, int, int, int, int) line: 338  
        PhoneWindow$DecorView(View).layout(int, int, int, int) line: 7192   
        ViewRoot.performTraversals() line: 1145 
        ViewRoot.handleMessage(Message) line: 1865  
        ViewRoot(Handler).dispatchMessage(Message) line: 99 
        Looper.loop() line: 130 
        ActivityThread.main(String[]) line: 3835    
        Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]  
        Method.invoke(Object, Object...) line: 507  
        ZygoteInit$MethodAndArgsCaller.run() line: 847  
        ZygoteInit.main(String[]) line: 605 
        NativeStart.main(String[]) line: not available [native method]  
    
    Thread[main](挂起(在BitmapDrawable中进入方法onBoundsChange))
    BitmapDrawable.onBoundsChange(Rect)行:293
    BitmapDrawable(Drawable).setBounds(int,int,int,int)行:131
    ImageView.configureBounds()行:769
    设置帧(int,int,int,int)行:742
    图像视图(视图)。布局(int,int,int,int)行:7186
    setChildFrame(视图,int,int,int,int)行:1254
    LinearLayout.layoutVertical()行:1130
    线性布局。仅布局(布尔,int,int,int,int)行:1047
    线性布局(视图)。布局(int,int,int,int)线:7192
    FrameLayout.onLayout(boolean,int,int,int,int)行:338
    框架布局(视图)。布局(int,int,int,int)行:7192
    setChildFrame(视图,int,int,int,int)行:1254
    LinearLayout.layoutVertical()行:1130
    线性布局。仅布局(布尔,int,int,int,int)行:1047
    线性布局(视图)。布局(int,int,int,int)线:7192
    PhoneWindow$DecorView(框架布局)。仅布局(布尔值,int,int,int,
    
    <activity
                android:label="@string/app_name"
                android:name=".RotateActivity" 
                android:configChanges="orientation|keyboardHidden">
                <intent-filter >
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
    super.onConfigurationChanged(newConfig); // super called before initialize()
    mConfig = newConfig;
    initialize();
    
    Thread [<1> main] (Suspended (entry into method onBoundsChange in BitmapDrawable))  
        BitmapDrawable.onBoundsChange(Rect) line: 293   
        BitmapDrawable(Drawable).setBounds(int, int, int, int) line: 131    
        ImageView.configureBounds() line: 769   
        ImageView.setFrame(int, int, int, int) line: 742    
        ImageView(View).layout(int, int, int, int) line: 7186   
        LinearLayout.setChildFrame(View, int, int, int, int) line: 1254 
        LinearLayout.layoutVertical() line: 1130    
        LinearLayout.onLayout(boolean, int, int, int, int) line: 1047   
        LinearLayout(View).layout(int, int, int, int) line: 7192    
        FrameLayout.onLayout(boolean, int, int, int, int) line: 338 
        FrameLayout(View).layout(int, int, int, int) line: 7192 
        LinearLayout.setChildFrame(View, int, int, int, int) line: 1254 
        LinearLayout.layoutVertical() line: 1130    
        LinearLayout.onLayout(boolean, int, int, int, int) line: 1047   
        LinearLayout(View).layout(int, int, int, int) line: 7192    
        PhoneWindow$DecorView(FrameLayout).onLayout(boolean, int, int, int, int) line: 338  
        PhoneWindow$DecorView(View).layout(int, int, int, int) line: 7192   
        ViewRoot.performTraversals() line: 1145 
        ViewRoot.handleMessage(Message) line: 1865  
        ViewRoot(Handler).dispatchMessage(Message) line: 99 
        Looper.loop() line: 130 
        ActivityThread.main(String[]) line: 3835    
        Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]  
        Method.invoke(Object, Object...) line: 507  
        ZygoteInit$MethodAndArgsCaller.run() line: 847  
        ZygoteInit.main(String[]) line: 605 
        NativeStart.main(String[]) line: not available [native method]