开源 _ Scene:Android 开源页面导航和组合框架

GroupScene

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Scene 使用

简单使用

这里介绍简单的上手,更多用法见 Github 仓库的示例。

接入

添加依赖:

dependencies {
implementation ‘com.bytedance.scene:scene: l a t e s t v e r s i o n ′ i m p l e m e n t a t i o n ′ c o m . b y t e d a n c e . s c e n e : s c e n e − u i : latest_version' implementation 'com.bytedance.scene:scene-ui: latestversionimplementationcom.bytedance.scene:sceneui:latest_version’
implementation ‘com.bytedance.scene:scene-shared-element-animation:$latest_version’

// Kotlin
implementation ‘com.bytedance.scene:scene-ktx:$latest_version’
}

创建首页:

class MainScene : AppCompatScene() {
override fun onCreateContentView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View? {
return View(requireSceneContext())
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setTitle(“Main”)
toolbar?.navigationIcon = null
}
}

创建 Activity:

class MainActivity : SceneActivity() {
override fun getHomeSceneClass(): Class {
return MainScene::class.java
}

override fun supportRestore(): Boolean {
return false
}
}

添加到 Manifest.xml,注意把输入法模式也改了:






运行就可以了。

这是新应用想全部使用 Scene 写的方式。如果是老应用重构迁移,或者只想用页面组合替代 Fragment,导航依旧用 Activity 的做法,可以见 Github 的 Demo。

导航

打开新页面:

requireNavigationScene().push(TargetScene::class.java)

返回:

requireNavigationScene().pop()

打开页面拿结果:

requireNavigationScene().push(TargetScene::class.java, null,
PushOptions.Builder().setPushResultCallback { result ->
}
}.build())

设置结果:

requireNavigationScene().setResult(this@TargetScene, YOUR_RESULT)

组合

组合的 API 类似 Fragment,继承 GroupScene,然后可以操作任意 Scene 添加到自己的 View 布局内:

void add(@IdRes int viewId, @NonNull Scene childScene, @NonNull String tag);
void remove(@NonNull Scene childScene);
void show(@NonNull Scene childScene);
void hide(@NonNull Scene childScene);
@Nullable
T findSceneByTag(@NonNull String tag);

示例:

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
}
}

通讯

Scene 支持 ViewModel,可以通过 by activityViewModels,by viewModels 拿到托管到 Activity 或者自己的 ViewModel:

class ViewModelSceneSamples : GroupScene() {
private val viewModel: SampleViewModel by activityViewModels()

示例:

class ViewModelSceneSamples : GroupScene() {
private val viewModel: SampleViewModel by activityViewModels()
private lateinit var textView: TextView

override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel.counter.observe(this, Observer { t -> textView.text = “” + t })

add(R.id.child, ViewModelSceneSamplesChild(), “Child”)
}
}

class ViewModelSceneSamplesChild : Scene() {
private val viewModel: SampleViewModel by activityViewModels()

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View {
return Button(requireSceneContext()).apply {
text = “Click to +1”
}
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
requireView().setOnClickListener {
val countValue = viewModel.counter.value ?: 0
viewModel.counter.value = countValue + 1
}
}
}

class SampleViewModel : ViewModel() {
val counter: MutableLiveData = MutableLiveData()
}

动画

在 Push 的时候,通过 PushOptions 可以配置简单的过场动画:

val enter = R.anim.slide_in_from_right
val exit = R.anim.slide_out_to_left
requireNavigationScene().push(TargetScene::class.java, null,
PushOptions.Builder().setAnimation(requireActivity(), enter, exit).build())

复杂的共享元素动画,手势动画,参考 Demo。

右划返回

Scene 内置右划返回手势,你直接继承 AppCompatScene,然后打开手势:

setSwipeEnabled(true)

核心设计思路

  1. Scene 本身是在 View 上面包一层生命周期,通过一个叫 LifeCycleFragment 的原生 Fragment 分发生命周期事件给框架内部,再由父组件同步给子组件。
  2. 父子组件同步生命周期,在原则上:
  • 进入的时候,先执行父组件的生命周期回调,再执行子组件的生命周期回调;
  • 退出的时候,先执行子组件的生命周期回调,再执行父组件的生命周期回调;
  1. NavigationScene 负责导航栈的处理,GroupScene 负责页面组合的处理,有点类似 iOS 的 UINavigationController/UIViewController,WinRT 的 Page。拆分的原因,是出于考虑性能,因为导航这个任务,由于动画的要求,本身的层级就会比普通的页面组合复杂,动画的 API 也更加强大。这两件事情,本身影响的生命周期也不一样,导航会影响之前的页面,而组合并不会。
  2. 生命周期和动画的处理原则是,先执行完生命周期,然后拿前后两个页面的 View 做动画,所以避免了Activity 动画需要在页面之间来回传递 Bitmap 来模拟控件这种繁琐的步骤,也避免了 Activity 动画黑屏的问题。
  3. 最后再由于 Transition 库过于无力,所以用系统核心的 GhostView,Scene 重头实现一遍共享元素动画。

未来与总结

Scene Router,开发中,以便可以支持流行的 Android 组件化开发。

Scene Dialog,开发中,用于解决 Android 框架的 Dialog 因为是基于 Window 会盖在普通的 View 之上的问题。

关于单 Activity 的想法,业界早在 Fragment 刚推出的时候就有探讨,社区诞生了 Conductor 之类的框架,甚至这2年,Google 官方也在做 Navigation Component,但是毕竟 Fragment 的坑太大,基于Fragment 做导航,总免不了受限于 Fragment 的兼容性,以至于后来,Google 为了解决这些兼容性问题,直接打算魔改 Fragment,废掉之前用了很多年的接口。

基于 View 重新实现的导航和组合方案,一方面是没有之前的技术债,一方面可以跳出 Google 的想法,比如说可以控制状态保存的范围,来实现更加强大的动画能力和组件通讯能力,这是官方的组件不会提供给开发者的。
仓库中的 Demo,已经把 Android 日常开发中大部分场景都补了示例,没有在本文中列出来的功能,可以参考 Demo 的写法。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

建议

当我们出去找工作,或者准备找工作的时候,我们一定要想,我面试的目标是什么,我自己的技术栈有哪些,近期能掌握的有哪些,我的哪些短板 ,列出来,有计划的去完成,别看前两天掘金一些大佬在驳来驳去 ,他们的观点是他们的,不要因为他们的观点,膨胀了自己,影响自己的学习节奏。基础很大程度决定你自己技术层次的厚度,你再熟练框架也好,也会比你便宜的,性价比高的替代,很现实的问题但也要有危机意识,当我们年级大了,有哪些亮点,与比我们经历更旺盛的年轻小工程师,竞争。

  • 无论你现在水平怎么样一定要 持续学习 没有鸡汤,别人看起来的毫不费力,其实费了很大力,这四个字就是我的建议!!!!!!!!!

  • 准备想说怎么样写简历,想象算了,我觉得,技术就是你最好的简历

  • 我希望每一个努力生活的it工程师,都会得到自己想要的,因为我们很辛苦,我们应得的。

  • 有什么问题想交流,欢迎给我私信,欢迎评论

【附】相关架构及资料

Android高级技术大纲

面试资料整理

内含往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

w1QPoE-1712408595239)]

[外链图片转存中…(img-rr5HGSr4-1712408595239)]

内含往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
  • 12
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值