<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Scene導航和頁面切分組件庫

          聯(lián)合創(chuàng)作 · 2023-09-24 06:11

          Scene 是字節(jié)跳動開源的一個基于 View 的輕量級導航和頁面切分組件庫,主要特性:

          1. 簡單方便的頁面導航和棧管理,支持MultiStack
          2. 完善的生命周期的管理和分發(fā)
          3. 可以更簡單的實現(xiàn)復雜的過場動畫
          4. 支持對Activity和Window屬性的修改和恢復
          5. 支持頁面之間拿返回值,支持在Scene中申請權限
          6. 支持頁面銷毀時保存狀態(tài)和恢復

          介紹

          Scene 旨在導航和頁面切分上替代Activity和Fragment的使用。

          Activity目前存在的主要問題:

          1. 棧管理弱,Intent和LaunchMode混亂,即使各種Hack仍然不能完全避免黑屏等問題
          2. Activity的性能較差,普通的空白頁面啟動也平均60ms以上(三星S9測試)
          3. 因為Activity被強制需要支持銷毀恢復,導致了一些問題:
            • 轉場動畫能力有限,無法實現(xiàn)較復雜的交互動畫,
            • 共享元素動畫基本不可用,有Framework層的崩潰無法解決
            • 每次啟動新的Activity,都需要上個頁面執(zhí)行完onSaveInstance,損失性能
          4. Activity依賴Manifest文件導致注入困難,動態(tài)化需要各種Hack

          Fragment目前存在的主要問題:

          1. 官方長期無法解決的崩潰較多,即使不用Fragment,在AppCompatActivity的onBackPressed()中仍然可能觸發(fā)崩潰
          2. add/remove/hide/show操作不是立刻執(zhí)行,在嵌套時即使使用commitNow也不能保證子Fragment狀態(tài)更新
          3. 動畫支持糟糕,頁面切換時無法保證Z軸順序
          4. 導航功能很弱,除了基本的打開和關閉,高級的棧管理
          5. 原生Fragment和Support v4包中的Fragment的生命周期并不完全相同

          Scene框架嘗試去解決上面提到的Activity和Fragment存在的問題

          提供簡單可靠、易擴展的API,來實現(xiàn)一套輕量的導航和頁面切分解決方案

          同時我們提供了一系列的遷移方案,來幫助開發(fā)者漸進式地從Activity和Fragment遷移到Scene。

          Get Started

          在依賴中添加:

          implementation 'com.bytedance.scene:scene:$latest_version'
          implementation 'com.bytedance.scene:scene-ui:$latest_version'
          implementation 'com.bytedance.scene:scene-shared-element-animation:$latest_version'
          implementation 'com.bytedance.scene:scene-ktx:$latest_version'

          Scene有2個子類:NavigationScene和GroupScene,其中:

          1. NavigationScene支持頁面切換
          2. GroupScene支持頁面切分
          Scene NavigationScene GroupScene

          簡單的接入,讓主Activity繼承于SceneActivity即可:

          class MainActivity : SceneActivity() {
              override fun getHomeSceneClass(): Class<out Scene> {
                  return MainScene::class.java
              }
          
              override fun supportRestore(): Boolean {
                  return false
              }
          }

          一個簡單的Scene示例:

          class MainScene : AppCompatScene() {
              private lateinit var mButton: Button
              override fun onCreateContentView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View? {
                  val frameLayout = FrameLayout(requireSceneContext())
                  mButton = Button(requireSceneContext())
                  mButton.text = "Click"
                  frameLayout.addView(mButton, FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT))
                  return frameLayout
              }
          
              override fun onActivityCreated(savedInstanceState: Bundle?) {
                  super.onActivityCreated(savedInstanceState)
                  setTitle("Main")
                  toolbar?.navigationIcon = null
                  mButton.setOnClickListener {
                      navigationScene?.push(SecondScene())
                  }
              }
          }
          
          class SecondScene : AppCompatScene() {
              private val mId: Int by lazy { View.generateViewId() }
          
              override fun onCreateContentView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View? {
                  val frameLayout = FrameLayout(requireSceneContext())
                  frameLayout.id = mId
                  return frameLayout
              }
          
              override fun onActivityCreated(savedInstanceState: Bundle?) {
                  super.onActivityCreated(savedInstanceState)
                  setTitle("Second")
                  add(mId, ChildScene(), "TAG")
              }
          }
          
          class ChildScene : Scene() {
              override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View {
                  val view = View(requireSceneContext())
                  view.setBackgroundColor(Color.GREEN)
                  return view
              }
          }

          Migration to Scene

          一個新的App可以通過直接繼承SceneActivity的方式接入Scene,

          但如果已有的Activity不方便更改繼承關系,則可參考SceneActivity的代碼直接使用SceneDelegate來處理,

          以西瓜視頻的首頁遷移方案為例:

          首先在首頁的XML申明一個存放Scene的布局:scene_container

          <?xml version="1.0" encoding="utf-8"?>
          <merge xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
           
              <...>
              
              <...>
          
              <!-- 上面是這個Activity的已有布局 -->
           
              <FrameLayout
                  android:id="@+id/scene_container"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent" />
           
          </merge>

          再創(chuàng)建一個透明的Scene作為根Scene

          public static class EmptyHolderScene extends Scene {
              @NonNull
              @Override
              public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
                  return new View(getActivity());
              }
           
              @Override
              public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
                  super.onViewCreated(view, savedInstanceState);
                  getView().setBackgroundColor(Color.TRANSPARENT);
              }
           
              @Override
              public void onActivityCreated(@Nullable Bundle savedInstanceState) {
                  super.onActivityCreated(savedInstanceState);
                  ArticleMainActivity activity = (ArticleMainActivity) requireActivity();
                  activity.createSceneLifecycleCallbacksToDispatchLifecycle(getNavigationScene());
              }
          }

          綁定這個透明的Scene到 R.id.scene_container

          mSceneActivityDelegate = NavigationSceneUtility.setupWithActivity(this, R.id.scene_container, null,
                  new NavigationSceneOptions().setDrawWindowBackground(false)
                          .setFixSceneWindowBackgroundEnabled(true)
                          .setSceneBackground(R.color.material_default_window_bg)
                          .setRootScene(EmptyHolderScene.class, null), false);

          實質上是有個透明的Scene蓋在首頁,但是視覺上看不出來

          然后在Activity中提供Push的方法

          public void push(@NonNull Class<? extends Scene> clazz, @Nullable Bundle argument, @Nullable PushOptions pushOptions) {
              if (mSceneActivityDelegate != null) {
                  mSceneActivityDelegate.getNavigationScene().push(clazz, argument, pushOptions);
              }
          }

          這樣就基本遷移完成,可以在這個Activity中直接打開新的Scene頁面了。

          Issues

          由于Scene是基于View來實現(xiàn)其功能的,有一些已知但暫時無法解決的問題:

          Dialog

          一個正常Dialog的Window是獨立于并蓋在Activity的Window之上的,

          所以如果在Dialog中點擊打開一個Scene,就會導致Scene出現(xiàn)在Dialog后面。

          可以選擇點擊的時候關閉對話框,也可以選擇使用Scene來實現(xiàn)對話框,來替代系統(tǒng)的Dialog。

          SurfaceView and TextureView

          在Scene返回時,會先執(zhí)行Scene的生命周期后執(zhí)行動畫,

          但是如果遇到SurfaceView/TextureView,這個過程會導致SurfaceView/TextureView黑屏,

          對于TextureView可以選擇結束前,獲得Surface,動畫前把這個Surface重新賦值

          對于SurfaceView,結束前,捕獲Bitmap,設置到ImageView,這個過程中因為涉及大的Bitmap創(chuàng)建,

          可以Try catch,然后在動畫結束后回收這個Bitmap。

          Status Bar related

          劉海屏在Android P之前沒有官方API,各個廠商有自己的實現(xiàn)

          如果用Window Flag或View UiVisibility來隱藏狀態(tài)欄圖標,都會引發(fā)整個Activity的重新布局,

          這同時也會導致Scene頁面的位置變化,某些情況下可能會有不符合預期的行為

           

          瀏覽 34
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          編輯 分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          編輯 分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  美女尻屄视频 | 啊啊草,在厕所操视频 | 大香蕉日逼 | 91九色啦 | 玖玖性爱|