Scene 是字节跳动开源的一个基于 View 的轻量级导航和页面切分组件库,主要特性:
Scene 旨在导航和页面切分上替代Activity和Fragment的使用。
Activity目前存在的主要问题:
Fragment目前存在的主要问题:
Scene框架尝试去解决上面提到的Activity和Fragment存在的问题
提供简单可靠、易扩展的API,来实现一套轻量的导航和页面切分解决方案
同时我们提供了一系列的迁移方案,来帮助开发者渐进式地从Activity和Fragment迁移到Scene。
在依赖中添加:
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,其中:
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 } }
一个新的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>
再创建一个透明的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页面了。
由于Scene是基于View来实现其功能的,有一些已知但暂时无法解决的问题:
一个正常Dialog的Window是独立于并盖在Activity的Window之上的,
所以如果在Dialog中点击打开一个Scene,就会导致Scene出现在Dialog后面。
可以选择点击的时候关闭对话框,也可以选择使用Scene来实现对话框,来替代系统的Dialog。
在Scene返回时,会先执行Scene的生命周期后执行动画,
但是如果遇到SurfaceView/TextureView,这个过程会导致SurfaceView/TextureView黑屏,
对于TextureView可以选择结束前,获得Surface,动画前把这个Surface重新赋值
对于SurfaceView,结束前,捕获Bitmap,设置到ImageView,这个过程中因为涉及大的Bitmap创建,
可以Try catch,然后在动画结束后回收这个Bitmap。
刘海屏在Android P之前没有官方API,各个厂商有自己的实现
如果用Window Flag或View UiVisibility来隐藏状态栏图标,都会引发整个Activity的重新布局,
这同时也会导致Scene页面的位置变化,某些情况下可能会有不符合预期的行为
对于搜索引擎或电子商务网站,常常将信息分页显示,这样可以减少页面大小,进而提高页面的加载速度。分页显示后,就需要通过分页导航来告诉用户要浏览的信息量,方便用户快速跳过一些不想看的信息,也便于定位和查找。因此,分页导航也是很常见的、很重要的一种导航。 实际上,分页导航的制作方法也很简单。分页导航一般包括上一页、页码、下一页三部分。首先,创建一个容器,来包裹分页导航的链接。如: <div class
导航组件说明 组件 说明 最低版本 navigator 页面链接 1.0.0 functional-page-navigator 用于跳转插件功能页 不支持 navigator 属性 类型 默认值 必填 说明 最低版本 url string 否 当前小程序内的跳转链接 open-type navigate 否 跳转方式 hover-class string navigator-hover 否 指定
我正在一个新的Android应用程序上使用导航组件,但我不知道怎么做 首先,我有我的主活动,我有main_navigation_graph 主要活动 NavHostFragment main_navigation_graph里面有3个碎片 这里一切都很好。问题是当我到达最后一个片段时,因为在这个片段上,我想根据BottomNavigationView输入(暂时)显示一些子片段(在新的NavHost
导航规则是JSF Framework提供的那些规则,用于描述单击按钮或链接时要显示的视图。 可以在名为faces-config.xml的JSF配置文件中定义导航规则。 它们可以在托管bean中定义。 导航规则可以包含可以显示结果视图的条件。 JSF 2.0也提供隐式导航,其中不需要定义导航规则。 隐式导航 JSF 2.0提供了名为implicit navigation auto view page
我有一个非常简单的应用程序,由三个片段和一个底部导航栏组成,使用“New Project”创建- 有没有“标准”的方法来做到这一点? 我尝试过: 使用导航组件的,它似乎启动了带有自己的后栈的片段并破坏了底部导航。 以不同的方式使用,这要么导致异常,要么以不同的方式破坏底部导航。 在这篇帖子中,有人问了完全相同的问题,但被标记为重复。我没有找到答案,尤其是关于导航组件。
问题内容: 我已经使用facelets模板完成了一个基本的JSF应用程序。我的模板如下: 然后,我有一个 主页 (如下所示),它导航到 第二页 。两个页面都使用上面的模板。 如果我在faces-config.xml中使用它,它将进行导航,但是将重新加载 整个 页面。我的问题是: 有没有一种方法可以从页面导航到另一个仅更新模板部分的内容?(同时保留页面的其余部分不变) 谢谢! 问题答案: 您可以通过
实际上,我正在我的应用程序中使用新的架构组件,并且我已经设置了导航组件。我有一个导航抽屉,我想用它。我已经设置好了,但我面临一些问题: 1-抽屉不会自动关闭。菜单正常工作并导航到正确的位置,但导航后不会关闭。我必须添加一个目的地ChangedListener才能自己关闭它。 在代码实验室里,抽屉自动关闭,我真的不明白为什么。 2-向上按钮打开抽屉。当我导航到非顶级片段时,菜单图标变为向上箭头,但当
Navigate the Scene View quickly and efficiently with the Scene View controls. 利用场景视图控制器快速有效地操控场景视图。 Arrow Movement 用箭头移动 Use Arrow Keys to move around the scene. Holding down Shift will make you move