Existe-t-il un moyen d'utiliser la fonction d'image dans l'image sur une activité qui n'est pas une vidéo pour la montrer à la baisse?
J'ai une activité avec une barre de progression géante et du texte que je voudrais afficher sur la fenêtre PiP pendant que l'utilisateur a navigué sur le Web.
J'ai déjà
@Override protected void onUserLeaveHint() { PictureInPictureParams params = new PictureInPictureParams.Builder() .build(); enterPictureInPictureMode(params); }
défini pour l'activité dans le manifeste.
et pour démarrer PiP
android:supportsPictureInPicture="true" android:configChanges="screenSize|smallestScreenSize|screenLayout"
Voici à quoi ressemble mon exemple d'application
J'appuie sur home et cela s'anime brièvement à
puis se redessine rapidement pour devenir p>
J'espère montrer PiP tel qu'il apparaît réduit dans l'image n ° 2 mais après une animation rapide, il se redessine à ce à quoi il ressemble dans l'image n ° 3.
Est-il possible d'obtenir une vue réduite?
Veuillez garder à l'esprit que ce ne sera pas une application de l'App Store. C'est une application très ciblée sur une tablette dédiée.
4 Réponses :
Peut-être un peu hacky, mais vous pouvez changer le DPI au moment de l'exécution.
Le code suivant utilise onPictureInPictureModeChanged ()
pour écouter un changement de mode et changer le DPI au prochain redémarrage. p>
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; }
Parce que onUserLeaveHint ()
- qui démarre le mode PIP - est appelé après onSaveInstanceState ()
le mode actuel ne peut pas être stocké dans un champ de la classe d'activité. Il doit être stocké ailleurs où il survit à un changement de configuration. Un champ dans la classe d'application est utilisé ici.
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; } } }
(Il n'est pas nécessaire d'empêcher les changements de configuration avec android: configChanges
.)
Résultat:
Pas besoin d'inclure les configChanges dans le manifeste.
<activity android:name=".PictureIPActivity" android:resizeableActivity="true" android:launchMode="singleTask" android:supportsPictureInPicture="true">
La clé pour redimensionner l'animation est les paramètres dans le fichier AndroidManifest.xml
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)); } }
Chaque fois que l ' Activité
entre ou sort du mode PIP, elle est détruite et recréée (c'est le comportement que j'ai noté). La différence entre l'animation et le résultat final est que lors de l'entrée en mode PIP, le système s'anime en réduisant l'activité et ses composants d'interface utilisateur.
Lorsque l'activité est recréée, elle utilise la même mise en page que vous avez fournie lors de la création initiale de l'activité. avec les mêmes dimensions, le problème est que la configuration de l ' activité
a changé et que l'appareil est entré dans une configuration de taille plus petite, c'est-à-dire dans votre cas de xlarge à petit ou normal.
Maintenant que nous savons que l ' activité
est détruite, vous pouvez gérer les changements de taille d'écran comme vous le faites habituellement.
Voici ce que vous pouvez faire:
onPictureInPictureModeChanged ()
. J'ai obtenu le résultat souhaité en ajoutant un nouveau dossier dimens-small
. Vous pouvez en choisir un pour vous-même. Ce dimens.xml contiendra le android: textSize = "@ dimen / textSize"
pour le petit écran.
Maintenant que cela est fait, voici la raison pour laquelle vous ne l'avez probablement pas ne cherchez pas les loisirs: selon les Docs PIP a >
spécifiez que votre activité gère les changements de configuration de mise en page afin que votre activité ne soit pas relancée lorsque des modifications de mise en page se produisent pendant les transitions en mode PIP.
Et même si j'ai ajouté
android:resizeableActivity="true" android:supportsPictureInPicture="true" android:configChanges="screenSize|smallestScreenSize|screenLayout"
dans ma balise
dans le manifeste mon Activité code> était toujours recréé à la fin de chaque changement de mode.
Ce qui est soit un bogue, soit quelque chose qui manque dans la documentation ou dans le code. Ou peut-être une déclaration peu claire pour les transitions / animations uniquement et non le résultat final réel.
Voici une autre solution qui utilise des fragments pour afficher une interface utilisateur mise à l'échelle. Contrairement à ma solution précédente , cette solution a l'avantage d'être capable d'afficher une interface utilisateur optimisée pour le mode PIP. (Par exemple, certaines vues peuvent être masquées en mode PIP.)
Le code suivant utilise onPictureInPictureModeChanged () pour écouter un changement de mode et change l'interface utilisateur au prochain redémarrage. (Parce que la barre d'outils n'est pas nécessaire en mode PIP, elle est masquée avant que le mode PIP soit entré.)
<?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>
Parce que onUserLeaveHint () - qui démarre le mode PIP - est appelé après onSaveInstanceState (), le mode actuel ne peut pas être stocké dans un champ de la classe d'activité. Il doit être stocké ailleurs où il survit à un changement de configuration. Un champ de la classe d'application est utilisé ici.
<?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="🙂" android:textSize="28sp" /> </RelativeLayout>
Disposition des fragments pour le mode plein écran:
public class MyApplication extends Application { public boolean inPipMode = false; }
Disposition des fragments pour Mode 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); } }
Résultat: