Android画中画比例视图

时间:2019-02-19 21:15:06

标签: android picture-in-picture

是否有一种方法可以在不是视频的活动中使用画中画功能来将其按比例缩小?

我有一个带有巨大进度条的活动,并且我想在用户进行一些Web浏览时在PiP窗口上显示一些文本。

我已经有

android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout"

为清单中的活动设置。

并启动PiP

@Override
protected void onUserLeaveHint() {


    PictureInPictureParams params = new PictureInPictureParams.Builder()
            .build();
    enterPictureInPictureMode(params);

}

这是我的示例应用程序的样子

enter image description here

我按home键,它简短地动画到

enter image description here

然后迅速重绘成为

enter image description here

我希望在图片#2中按比例缩小画中画,但是在快速动画播放后,它会重新绘制为图片#3中的样子。

反正有没有缩小视图的视图?

请记住,这不是一个应用商店应用。这是专用平板电脑上非常有针对性的应用程序。

3 个答案:

答案 0 :(得分:2)

也许有点棘手,但是您可以在运行时更改DPI。

以下代码使用onPictureInPictureModeChanged()来监听模式更改,并在下次重新启动时更改DPI。

public class Activity extends AppCompatActivity {

    private MyApplication mApplication;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mApplication = (MyApplication) getApplicationContext();

        if (mApplication.mode == MyApplication.MODE_NONE) {
            saveDpi();
        } else {
            setDpi();
        }

        setContentView(R.layout.activity);

        ...
    }

    private void saveDpi() {
        Configuration configuration = getResources().getConfiguration();
        mApplication.orgDensityDpi = configuration.densityDpi;
    }

    private void setDpi() {
        Configuration configuration = getResources().getConfiguration();
        DisplayMetrics metrics = getResources().getDisplayMetrics();
        if (mApplication.mode == MyApplication.MODE_PIP) {
            configuration.densityDpi = mApplication.orgDensityDpi / 3;
        } else {
            configuration.densityDpi = mApplication.orgDensityDpi;
        }
        getBaseContext().getResources().updateConfiguration(configuration, metrics);
    }

    @Override
    protected void onUserLeaveHint() {
        PictureInPictureParams params = new PictureInPictureParams.Builder().build();
        enterPictureInPictureMode(params);
    }

    @Override
    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
        if (isInPictureInPictureMode) {
            mApplication.mode = MyApplication.MODE_PIP;
        } else {
            mApplication.mode = MyApplication.MODE_FULL;
        }
    }

}

由于onUserLeaveHint()(启动PIP模式)在onSaveInstanceState()之后被调用,因此当前模式无法存储在活动类的字段中。必须将其存储在其他地方,以使其在配置更改后仍然存在。在此使用应用程序类中的字段。

public class MyApplication extends Application {

    public static final int MODE_NONE = 0;
    public static final int MODE_FULL = 1;
    public static final int MODE_PIP = 2;

    public int mode = MODE_NONE;
    public int orgDensityDpi = 0;

}

(无需阻止使用android:configChanges进行配置更改。)

结果:

result

答案 1 :(得分:1)

每当Activity进入或退出PIP模式时,它都会被销毁并重新创建(这是我注意到的行为)。动画和最终结果之间的差异是因为进入PIP模式时,系统会通过按比例缩小活动及其UI组件来进行动画制作。

重新创建活动时,它使用的是您在活动初始​​创建时提供的相同布局,并且具有相同的变暗度,问题是Activity的配置已更改,并且设备已进入较小尺寸的配置,即从xlarge到小型或普通配置。

因此,既然我们知道Activity被销毁了,您就可以像平常一样处理屏幕尺寸更改。

这是您可以做的:

  1. 为新配置提供新的布局。
  2. 为新配置提供新的文本大小。
  3. 在运行时通过onPictureInPictureModeChanged()回调提供新的文本大小。

我通过添加一个新的dimens-small文件夹达到了预期的效果。您可以自己选择一个。此dimens.xml将包含用于小屏幕的android:textSize="@dimen/textSize"


现在这样做是您可能不希望休闲的原因:根据PIP Docs

  

指定您的活动处理布局配置更改,以便在PIP模式转换期间发生布局更改时,您的活动不会重新启动。

即使我添加了

android:resizeableActivity="true"
android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout"

清单中我的<activity>标签中的我的Activity仍在每次模式更改结束时重新创建。

这是错误,还是文档或代码中缺少的内容。也许不清楚的声明仅用于过渡/动画,而不是实际的最终结果。

答案 2 :(得分:0)

这是另一个使用片段显示缩放的UI的解决方案。与我的previous solution不同,此解决方案的优势在于能够显示针对PIP模式进行了优化的UI。 (例如,某些视图可以在PIP模式下隐藏。)

以下代码使用onPictureInPictureModeChanged()侦听模式更改,并在下次重新启动时更改UI。 (因为在PIP模式下不需要工具栏,所以在进入PIP模式之前它是隐藏的。)

public class Activity extends AppCompatActivity {

    private static final String FRAGMENT_TAG_FULL = "fragment_full";
    private static final String FRAGMENT_TAG_PIP = "fragment_pip";

    private MyApplication mApplication;

    private Toolbar mToolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mApplication = (MyApplication) getApplicationContext();

        setContentView(R.layout.activity);

        mToolbar = findViewById(R.id.toolbar);
        setSupportActionBar(mToolbar);

        if (!mApplication.inPipMode) {
            showFullFragment();
        } else {
            showPipFragment();
        }
    }

    @Override
    protected void onUserLeaveHint() {
        mToolbar.setVisibility(View.GONE);
        PictureInPictureParams params = new PictureInPictureParams.Builder().build();
        enterPictureInPictureMode(params);
    }

    @Override
    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
        if (isInPictureInPictureMode) {
            mApplication.inPipMode = true;
        } else {
            mApplication.inPipMode = false;
        }
    }

    private void showFullFragment() {
        Fragment fragment = new FragmentFull();
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container_content, fragment, FRAGMENT_TAG_FULL)
                .commit();
        mToolbar.setVisibility(View.VISIBLE);
    }

    private void showPipFragment() {
        Fragment fragment = new FragmentPip();
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container_content, fragment, FRAGMENT_TAG_PIP)
                .commit();
        mToolbar.setVisibility(View.GONE);
    }

}

因为onUserLeaveHint()-启动PIP模式-在onSaveInstanceState()之后被调用,所以当前模式无法存储在活动类的字段中。必须将其存储在其他地方,以使其在配置更改后仍然存在。在此使用应用程序类中的字段。

public class MyApplication extends Application {

    public boolean inPipMode = false;

}

全屏模式下的片段布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="Hello World!"
        android:textSize="36sp" />

    <TextView
        android:id="@+id/text_detail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/text"
        android:layout_centerHorizontal="true"
        android:text="&#x1F642;"
        android:textSize="28sp" />

</RelativeLayout>

PIP模式的片段布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="Hello World!"
        android:textSize="10sp"/>

</RelativeLayout>

结果:

result