10

有没有办法在不是视频的活动上使用画中画功能来显示它按比例缩小?

我有一个带有巨大进度条的活动和一些我想在用户浏览网页时在画中画窗口上显示的文本。

我已经有了

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

为清单中的活动设置。

并开始画中画

@Override
protected void onUserLeaveHint() {


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

}

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

在此处输入图像描述

我按回家,它会短暂地动画到

在此处输入图像描述

然后快速重绘成为

在此处输入图像描述

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

有没有办法实现缩小视图?

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

4

4 回答 4

6

也许有点 hacky,但你可以在运行时更改 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。)

结果:

结果

于 2019-03-10T17:37:30.977 回答
4

这是另一个使用片段显示缩放 UI 的解决方案。与我之前的解决方案不同,此解决方案的优势在于能够显示针对 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>

结果:

结果

于 2019-03-14T00:20:19.910 回答
3

无需在清单中包含 configChanges。

public class PictureIPActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);       
    setContentView(R.layout.activity_picture_ip);
    findViewById(R.id.tv_hello_world).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(mApplication, "enabling PiP", Toast.LENGTH_SHORT).show();
            enterPiPMode();
        }
    });
}

@Override
protected void onPause() {
    super.onPause();
    enterPiPMode();
}

private void enterPiPMode() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        PictureInPictureParams params = new PictureInPictureParams.Builder()
                .setAspectRatio(getPipRatio()).build();
        enterPictureInPictureMode(params);
    }
}

public Rational getPipRatio() {
 //   anything with aspect ration below 0.5 and above 2.5 (roughly) will be 
 unpractical or unpleasant to use
    DisplayMetrics metrics = getResources().getDisplayMetrics();
    return new Rational(Math.round(metrics.xdpi), Math.round(metrics.ydpi));
}
}

动画调整大小的关键是AndroidManifest.xml中的设置

  <activity android:name=".PictureIPActivity"
              android:resizeableActivity="true"
              android:launchMode="singleTask"
              android:supportsPictureInPicture="true">
于 2019-03-12T07:10:17.587 回答
1

每当Activity进入或退出 PIP 模式时,它都会被销毁并重新创建(这是我已经注意到的行为)。动画和最终结果之间的区别在于,当进入 PIP 模式时,系统会通过缩小 Activity 及其 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仍然在每次模式更改结束时重新创建。

要么是错误,要么是文档或代码中缺少的东西。或者可能只是对过渡/动画的不清楚的陈述,而不是实际的最终结果。

于 2019-03-12T10:27:23.813 回答