Android Sender UI 맞춤설정

색상을 설정하고 버튼, 텍스트, 썸네일 모양의 스타일을 지정하고 표시할 버튼 유형을 선택하여 Cast 위젯을 맞춤설정할 수 있습니다.

앱 테마 맞춤설정

이 예에서는 맞춤 색상, 소개 오버레이 스타일, 미니 컨트롤러 스타일, 확장된 컨트롤러 스타일을 정의할 수 있는 맞춤 테마 스타일 Theme.CastVideosTheme를 만듭니다.

<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Set AppCompat's color theming attrs -->
    <item name="colorPrimary">@color/primary</item>
    <item name="colorPrimaryDark">@color/primary_dark</item>
    <item name="colorAccent">@color/accent</item>
    <item name="android:textColorPrimary">@color/primary_text</item>
    <item name="android:textColorSecondary">@color/secondary_text</item>
    <item name="castIntroOverlayStyle">@style/CustomCastIntroOverlay</item>
    <item name="castMiniControllerStyle">@style/CustomCastMiniController</item>
    <item name="castExpandedControllerStyle">@style/CustomCastExpandedController</item>
</style>

위의 마지막 세 줄을 사용하면 이 테마의 일부로 소개 오버레이, 미니 컨트롤러, 확장 컨트롤러에 관한 스타일을 정의할 수 있습니다. 예시는 다음 섹션에 포함되어 있습니다.

전송 버튼 맞춤설정

앱의 테마에 맞춤 mediaRouteTheme를 추가하려면 다음 단계를 따르세요.

<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
  <!-- ... -->
  <item name="mediaRouteTheme">@style/CustomMediaRouterTheme</item>
</style>

맞춤 Media Router 테마를 선언하고 맞춤 mediaRouteButtonStyle를 선언합니다.

<style name="CustomMediaRouterTheme" parent="Theme.MediaRouter">
  <item name="mediaRouteButtonStyle">@style/CustomMediaRouteButtonStyle</item>
</style>

<style name="CustomMediaRouteButtonStyle" parent="Widget.MediaRouter.Light.MediaRouteButton">
  <item name="mediaRouteButtonTint">#EEFF41</item>
</style>

지원 라이브러리 버전이 26.0.0보다 최신인 경우 setTint를 사용해야 합니다. 이전 지원 라이브러리 버전의 경우 대신 buttonTint를 사용하세요.

시작 오버레이 테마 맞춤설정

IntroductoryOverlay 클래스는 앱이 맞춤 테마에서 재정의할 수 있는 다양한 스타일 속성을 지원합니다. 이 예에서는 오버레이 위젯 위의 버튼과 제목의 텍스트 모양을 재정의하는 방법을 보여줍니다.

<style name="CustomCastIntroOverlay" parent="CastIntroOverlay">
    <item name="castButtonTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Button</item>
    <item name="castTitleTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Title</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Button" parent="android:style/TextAppearance">
    <item name="android:textColor">#FFFFFF</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Title"parent="android:style/TextAppearance.Large">
    <item name="android:textColor">#FFFFFF</item>
</style>

미니 컨트롤러 맞춤설정

테마 맞춤설정하기

MiniControllerFragment 클래스는 앱이 맞춤 테마에서 재정의할 수 있는 다양한 스타일 속성을 지원합니다. 이 예에서는 썸네일 이미지 표시를 사용 설정하고, 부제와 자막의 텍스트 모양을 재정의하고, 색상을 설정하고, 버튼을 맞춤설정하는 방법을 보여줍니다.

<style name="CustomCastMiniController" parent="CastMiniController">
    <item name="castShowImageThumbnail">true</item>
    <item name="castTitleTextAppearance">@style/TextAppearance.AppCompat.Subhead</item>
    <item name="castSubtitleTextAppearance">@style/TextAppearance.AppCompat.Caption</item>
    <item name="castBackground">#FFFFFF</item>
    <item name="castProgressBarColor">#FFFFFF</item>
    <item name="castPlayButtonDrawable">@drawable/cast_ic_mini_controller_play</item>
    <item name="castPauseButtonDrawable">@drawable/cast_ic_mini_controller_pause</item>
    <item name="castStopButtonDrawable">@drawable/cast_ic_mini_controller_stop</item>
    <item name="castLargePlayButtonDrawable">@drawable/cast_ic_mini_controller_play_large</item>
    <item name="castLargePauseButtonDrawable">@drawable/cast_ic_mini_controller_pause_large</item>
    <item name="castLargeStopButtonDrawable">@drawable/cast_ic_mini_controller_stop_large</item>
    <item name="castSkipPreviousButtonDrawable">@drawable/cast_ic_mini_controller_skip_prev</item>
    <item name="castSkipNextButtonDrawable">@drawable/cast_ic_mini_controller_skip_next</item>
    <item name="castRewind30ButtonDrawable">@drawable/cast_ic_mini_controller_rewind30</item>
    <item name="castForward30ButtonDrawable">@drawable/cast_ic_mini_controller_forward30</item>
    <item name="castMuteToggleButtonDrawable">@drawable/cast_ic_mini_controller_mute</item>
    <item name="castClosedCaptionsButtonDrawable">@drawable/cast_ic_mini_controller_closed_caption</item
</style>

버튼 선택

MiniControllerFragment에는 앨범 아트와 버튼 2개를 표시할 수 있는 슬롯 3개 또는 앨범 아트가 채워지지 않은 경우 컨트롤 버튼 3개가 있습니다.

SLOT  SLOT  SLOT
  1     2     3

기본적으로 프래그먼트에는 재생/일시중지 전환 버튼이 표시됩니다. 개발자는 castControlButtons 속성을 사용하여 표시할 버튼을 재정의할 수 있습니다. 지원되는 컨트롤 버튼은 ID 리소스로 정의됩니다.

버튼 유형 설명
@id/cast_button_type_empty 이 슬롯에 버튼을 배치하지 마세요.
@id/cast_button_type_custom 맞춤 버튼
@id/cast_button_type_play_pause_toggle 재생과 일시중지 간에 전환
@id/cast_button_type_skip_previous 대기열의 이전 항목으로 건너뜁니다.
@id/cast_button_type_skip_next 대기열의 다음 항목으로 건너뜁니다.
@id/cast_button_type_rewind_30_seconds 재생을 30초 되감습니다.
@id/cast_button_type_forward_30_seconds 재생을 30초 앞으로 건너뜁니다.
@id/cast_button_type_mute_toggle 수신기 음소거 및 음소거 해제
@id/cast_button_type_closed_caption 텍스트 및 오디오 트랙을 선택하는 대화상자를 엽니다.

다음은 앨범 아트, 재생/일시중지 전환 버튼, 앞으로 건너뛰기 버튼을 왼쪽에서 오른쪽으로 순서대로 사용하는 예입니다.

<array name="cast_mini_controller_control_buttons">
    <item>@id/cast_button_type_empty</item>
    <item>@id/cast_button_type_play_pause_toggle</item>
    <item>@id/cast_button_type_forward_30_seconds</item>
</array>
...
<fragment
    android:id="@+id/cast_mini_controller"
    ...
    app:castControlButtons="@array/cast_mini_controller_control_buttons"
    class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment">

경고: 이 배열은 정확히 3개의 항목을 포함해야 합니다. 그러지 않으면 런타임 예외가 발생합니다. 슬롯에 버튼을 표시하지 않으려면 @id/cast_button_type_empty를 사용하세요.

맞춤 버튼 추가

MiniControllerFragment는 '좋아요' 버튼과 같이 SDK에서 제공하지 않는 맞춤 컨트롤 버튼을 추가하는 것을 지원합니다. 단계는 다음과 같습니다.

  1. MiniControllerFragmentcastControlButtons 속성에서 @id/cast_button_type_custom를 사용하여 맞춤 버튼을 포함할 슬롯을 지정합니다.

  2. UIController의 서브클래스를 구현합니다. UIController에는 전송 세션 또는 미디어 세션의 상태가 변경될 때 SDK에서 호출하는 메서드가 포함되어 있습니다. UIController의 서브클래스는 ImageView를 매개변수 중 하나로 사용하고 필요에 따라 상태를 업데이트해야 합니다.

  3. MiniControllerFragment의 서브클래스를 만든 다음 onCreateView를 재정의하고 getButtonImageViewAt(int)를 호출하여 맞춤 버튼의 ImageView를 가져옵니다. 그런 다음 bindViewToUIController(View, UIController)를 호출하여 뷰를 맞춤 UIController와 연결합니다.

  4. 맞춤 버튼의 작업을 처리하는 방법은 맞춤 작업 추가MediaIntentReceiver를 참고하세요.

    다음은 슬롯 2의 버튼을 MyCustomUIController라는 UIController에 연결하는 예입니다.

// arrays.xml
<array name="cast_expanded_controller_control_buttons">
    <item>@id/cast_button_type_empty</item>
    <item>@id/cast_button_type_rewind_30_seconds</item>
    <item>@id/cast_button_type_custom</item>
    <item>@id/cast_button_type_empty</item>
</array>
Kotlin
// MyCustomUIController.kt
class MyCustomUIController(private val mView: View) : UIController() {
    override fun onMediaStatusUpdated() {
        // Update the state of mView based on the latest the media status.
        ...
        mView.visibility = View.INVISIBLE
        ...
    }
}

// MyMiniControllerFragment.kt
class MyMiniControllerFragment : MiniControllerFragment() {
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        super.onCreateView(inflater, container, savedInstanceState)
        val customButtonView = getButtonImageViewAt(2)
        val myCustomUiController = MyCustomUIController(customButtonView)
        uiMediaController.bindViewToUIController(customButtonView, myCustomUiController)
        ...
    }
}
Java
// MyCustomUIController.java
class MyCustomUIController extends UIController {
    private final View mView;

    public MyCustomUIController(View view) {
            mView = view;
    }

    @Override
    public onMediaStatusUpdated() {
        // Update the state of mView based on the latest the media status.
        ...
        mView.setVisibility(View.INVISIBLE);
        ...
    }
}

// MyMiniControllerFragment.java
class MyMiniControllerFragment extends MiniControllerFragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        ImageView customButtonView = getButtonImageViewAt(2);
        MyCustomUIController myCustomUiController = new MyCustomUIController(customButtonView);
        getUIMediaController().bindViewToUIController(customButtonView, myCustomUiController);
        ...
    }
}

확장된 컨트롤러 맞춤설정

테마 맞춤설정하기

확장된 컨트롤러의 Activity가 어두운 테마 툴바를 사용하는 경우 툴바에서 테마를 설정하여 밝은 텍스트와 밝은 아이콘 색상을 사용할 수 있습니다.

<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="castExpandedControllerToolbarStyle">
        @style/ThemeOverlay.AppCompat.Dark.ActionBar
    </item>
</style>

확장된 컨트롤러에 버튼을 그리는 데 사용되는 자체 이미지를 지정할 수 있습니다.

<style name="CustomCastExpandedController" parent="CastExpandedController">
    <item name="castButtonColor">@null</item>
    <item name="castPlayButtonDrawable">@drawable/cast_ic_expanded_controller_play</item>
    <item name="castPauseButtonDrawable">@drawable/cast_ic_expanded_controller_pause</item>
    <item name="castStopButtonDrawable">@drawable/cast_ic_expanded_controller_stop</item>
    <item name="castSkipPreviousButtonDrawable">@drawable/cast_ic_expanded_controller_skip_previous</item>
    <item name="castSkipNextButtonDrawable">@drawable/cast_ic_expanded_controller_skip_next</item>
    <item name="castRewind30ButtonDrawable">@drawable/cast_ic_expanded_controller_rewind30</item>
    <item name="castForward30ButtonDrawable">@drawable/cast_ic_expanded_controller_forward30</item>
</style>

버튼 선택

확장된 컨트롤러의 활동에는 컨트롤 버튼을 표시하는 슬롯이 5개 있습니다. 가운데 슬롯에는 항상 재생/일시중지 전환 버튼이 표시되며 구성할 수 없습니다. 나머지 4개의 슬롯은 왼쪽에서 오른쪽으로 발신자 앱에서 구성할 수 있습니다.

SLOT  SLOT  PLAY/PAUSE  SLOT  SLOT
  1     2     BUTTON      3     4

기본적으로 활동에는 왼쪽에서 오른쪽으로 자막 버튼, 이전 항목으로 건너뛰기 버튼, 다음 항목으로 건너뛰기 버튼, 음소거 전환 버튼이 4개의 슬롯에 표시됩니다. 개발자는 castControlButtons 속성을 사용하여 어떤 슬롯에 어떤 버튼을 표시할지 재정의할 수 있습니다. 지원되는 컨트롤 버튼 목록은 미니 컨트롤러 버튼의 버튼 유형과 동일한 ID 리소스로 정의됩니다.

다음은 두 번째 슬롯에 되감기 버튼을, 세 번째 슬롯에 빨리 감기 버튼을 배치하고 첫 번째 슬롯과 마지막 슬롯을 비워 두는 예입니다.

// arrays.xml
<array name="cast_expanded_controller_control_buttons">
    <item>@id/cast_button_type_empty</item>
    <item>@id/cast_button_type_rewind_30_seconds</item>
    <item>@id/cast_button_type_forward_30_seconds</item>
    <item>@id/cast_button_type_empty</item>
</array>
...
// styles.xml
<style name="Theme.MyTheme">
    <item name="castExpandedControllerStyle">
        @style/CustomCastExpandedController
    </item>
</style>
...
<style name="CustomCastExpandedController" parent="CastExpandedController">
    <item name="castControlButtons">
        @array/cast_expanded_controller_control_buttons
    </item>
</style>

배열에는 항목이 정확히 4개 포함되어야 합니다. 그렇지 않으면 런타임 예외가 발생합니다. 슬롯에 버튼을 표시하지 않으려면 @id/cast_button_type_empty를 사용하세요. CastContext는 이 활동의 수명 주기와 프레젠테이션을 관리할 수 있습니다.

맞춤 버튼 추가

ExpandedControllerActivity는 '좋아요' 버튼과 같이 SDK에서 제공하지 않는 맞춤 컨트롤 버튼을 추가하는 것을 지원합니다. 단계는 다음과 같습니다.

  1. ExpandedControllerActivitycastControlButtons 속성에서 @id/cast_button_type_custom를 사용하여 맞춤 버튼을 포함할 슬롯을 지정합니다. 그런 다음 getButtonImageViewAt(int)를 사용하여 해당 맞춤 버튼의 ImageView를 가져올 수 있습니다.

  2. UIController의 서브클래스를 구현합니다. UIController에는 전송 세션 또는 미디어 세션의 상태가 변경될 때 SDK에서 호출하는 메서드가 포함되어 있습니다. UIController의 서브클래스는 ImageView를 매개변수 중 하나로 사용하고 필요에 따라 상태를 업데이트해야 합니다.

  3. ExpandedControllerActivity를 서브클래스화한 다음 onCreate를 재정의하고 getButtonImageViewAt(int)를 호출하여 버튼의 뷰 객체를 가져옵니다. 그런 다음 bindViewToUIController(View, UIController)를 호출하여 뷰를 맞춤 UIController와 연결합니다.

  4. 맞춤 버튼의 작업을 처리하는 방법은 맞춤 작업 추가MediaIntentReceiver를 참고하세요.

다음은 슬롯 2의 버튼을 MyCustomUIController라는 UIController에 연결하는 예입니다.

// arrays.xml
<array name="cast_expanded_controller_control_buttons">
    <item>@id/cast_button_type_empty</item>
    <item>@id/cast_button_type_rewind_30_seconds</item>
    <item>@id/cast_button_type_custom</item>
    <item>@id/cast_button_type_empty</item>
</array>
Kotlin
// MyCustomUIController.kt
class MyCustomUIController(private val mView: View) : UIController() {
    override fun onMediaStatusUpdated() {
        // Update the state of mView based on the latest the media status.
        ...
        mView.visibility = View.INVISIBLE
        ...
    }
}

// MyExpandedControllerActivity.kt
internal class MyExpandedControllerActivity : ExpandedControllerActivity() {
    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val customButtonView = getButtonImageViewAt(2)
        val myCustomUiController = MyCustomUIController(customButtonView)
        uiMediaController.bindViewToUIController(customButtonView, myCustomUiController)
        ...
    }
}
Java
// MyCustomUIController.java
class MyCustomUIController extends UIController {
    private final View mView;

    public MyCustomUIController(View view) {
        mView = view;
    }

    @Override
    public onMediaStatusUpdated() {
        // Update the state of mView based on the latest the media status.
        ...
        mView.setVisibility(View.INVISIBLE);
        ...
    }
}

// MyExpandedControllerActivity.java
class MyExpandedControllerActivity extends ExpandedControllerActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ImageView customButtonView = getButtonImageViewAt(2);
        MyCustomUIController myCustomUiController = new MyCustomUIController(customButtonView);
        getUIMediaController().bindViewToUIController(customButtonView, myCustomUiController);
        ...
    }
}