Android в картинке в масштабе - PullRequest
0 голосов
/ 20 февраля 2019

Есть ли способ использовать функцию «картинка в картинке» в упражнении, которое не является видео, чтобы показать его уменьшенное изображение?

У меня есть упражнение с гигантским индикатором выполнения и некоторым текстом, который я хотел бынравится отображать в окне 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

Я нажимаюдома, и он кратко оживляется до

enter image description here

, а затем быстро перерисовывается, чтобы стать

enter image description here

Я надеюсь показать PiP в уменьшенном виде на рисунке №2, но после быстрой анимации он перерисовывается так, как это выглядит на рисунке №3.

Есть ли какой-либо способ уменьшить изображение?

Имейте в виду, что это не приложение для магазина приложений.Это очень целевое приложение на выделенном планшете.

Ответы [ 4 ]

0 голосов
/ 14 марта 2019

Вот еще одно решение, которое использует фрагменты для отображения масштабированного пользовательского интерфейса.В отличие от моего предыдущего решения , это решение имеет то преимущество, что может отображать пользовательский интерфейс, оптимизированный для режима PIP.(Например, некоторые виды могут быть скрыты в режиме PIP.)

Следующий код использует onPictureInPictureModeChanged () для прослушивания изменения режима и изменения пользовательского интерфейса при следующем перезапуске.(Поскольку панель инструментов не требуется в режиме 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

0 голосов
/ 12 марта 2019

Нет необходимости включать 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">
0 голосов
/ 12 марта 2019

Всякий раз, когда Activity входит или выходит из режима PIP, он уничтожается и воссоздается (это поведение, которое я заметил).Разница между анимацией и конечным результатом заключается в том, что при переходе в режим PIP система выполняет анимацию путем уменьшения действия и его компонентов пользовательского интерфейса.

При повторном создании действия используется тот же макет, который вы указали при первоначальном создании.из-за активности с теми же размерами, проблема в том, что конфигурация Activity изменилась, и устройство вошло в конфигурацию меньшего размера, т.е. в вашем случае от xlarge до маленького или обычного.

Тактеперь, когда мы знаем, что Activity уничтожено, вы можете обрабатывать изменения размера экрана, как обычно.

Вот что вы можете сделать:

  1. Предоставить новый макет для новогоконфигурация.
  2. Укажите новый размер текста для новых конфигураций.
  3. Укажите новый размер текста во время выполнения при onPictureInPictureModeChanged() обратном вызове.

Я достигжелаемый результат, добавив новую папку dimens-small.Вы можете выбрать один для себя.Этот размер. Xml будет содержать android:textSize="@dimen/textSize" для маленького экрана.


Теперь, когда это сделано, вот причина, по которой вы, вероятно, не искали отдых: согласно PIP Docs

указывает, что ваша активность обрабатывает изменения конфигурации макета, чтобы ваша активность не перезапускалась, когда изменения макета происходят при переходах в режиме PIP.

И даже если я добавил

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

в моем теге <activity> в манифесте, мой Activity все еще воссоздавался в конце каждого изменения режима.

Что является ошибкой или отсутствием в любом документеили код.Или, возможно, неясное утверждение только для переходов / анимаций, а не фактический конечный результат.

0 голосов
/ 10 марта 2019

Может быть, немного странно, но вы можете изменить 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

...