Giter VIP home page Giter VIP logo

scene's Introduction

Scene

简体中文版说明 >>>

GitHub license API

Scene is a lightweight library of navigation and ui composition based on view.

  1. Simple and convenient navigation and stack management, support multi-stack
  2. Improved lifecycle management and distribution
  3. Easier to implement complex cut-scenes animation
  4. Support properties modification and recovery of Activity and Window
  5. Support return value between Scenes, support request and grant permissions in Scene
  6. Support save and recovery state of Scene

Download the Demo

Apps using Scene

xigua douyin toutiao
Xigua Video Tik Tok Toutiao

Introduction

Scene is designed to replace the use of Activity and Fragment on navigation and page segmentation.

The main problems of Activity:

  1. The stack management of Activity is weak, Intent and LaunchMode are confusing, even if various of hacks still can't completely avoid issues like black screen
  2. The performance of Activity is poor, average startup time of an empty Activity is more than 60ms (on Samsung S9)
  3. Because the Activity is forced to support states recovery, it causes some problems:
    • Transition animation has limited ability, difficult to implement complex interactive animations.
    • Shared-element animation is basically unavailable, and there are some crashes unresolved in Android Framework.
    • Every time starting a new Activity, onSaveInstance() of the previous Activity must be executed completely first, which will lose much performance.
  4. Activity relies on the Manifest file to cause injection difficulties, which also result in that Activity dynamics requires a variety of hacks

The main problems of Fragment:

  1. There are many crashes that the Google official can't solve for a long time. Even if you don't use Fragment, it may still trigger a crash in the OnBackPressed() of AppCompatActivity.
  2. The add/remove/hide/show operation is not executed immediately. With nest Fragments even if you use commitNow(), the status update of the sub Fragments cannot be guaranteed.
  3. The support of animation is poor, Z-axis order cannot be guaranteed when switching
  4. Navigation management is weak, there is no advanced stack management except for basic push and pop
  5. The lifecycle of Fragment in native Fragment and Support-v4 packages is not exactly the same

The Scene framework tries to solve these problems of the Activity and Fragment mentioned above.

Provides a simple, reliable, and extensible API for a lightweight navigation and page segmentation solution

At the same time, we provide a series of migration solutions to help developers gradually migrate from Activity and Fragment to Scene.

Get Started

Add it to your root build.gradle at the end of repositories:

allprojects {
	repositories {
		...
		maven { url 'https://jitpack.io' }
	}
}

Add it to your build.gradle:

dependencies {
	implementation 'com.github.bytedance.scene:scene:$latest_version'
	implementation 'com.github.bytedance.scene:scene_navigation:$latest_version'
	implementation 'com.github.bytedance.scene:scene_ui:$latest_version'
	implementation 'com.github.bytedance.scene:scene_dialog:$latest_version'
	implementation 'com.github.bytedance.scene:scene_shared_element_animation:$latest_version'
	implementation 'com.github.bytedance.scene:scene_ktx:$latest_version'
}

Scene has 2 subclasses: NavigationScene and GroupScene:

  1. NavigationScene supports navigation
  2. GroupScene supports ui composition
Scene NavigationScene GroupScene

For simple usage, just let your Activity inherit from SceneActivity:

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

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

A simple Scene example:

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

A new app can use Scene by directly inheriting the SceneActivity.

But if your existing Activity is not convenient to change the inheritance relationship, you can directly using SceneDelegate to handle Scenes refer to the code of SceneActivity.

Take the homepage migration plan of XiguaVideo as an example:

First, declares a layout in the XML of the home Activity for storing the 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">
 
    <...>
    
    <...>
 
    <!-- The above is the existing layout of the Activity -->
 
    <FrameLayout
        android:id="@+id/scene_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
 
</merge>

Then create a transparent Scene as the root 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());
    }
}

Bind this transparent Scene to 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);

In essence, there is a transparent Scene cover on the Activity, but it is not visually visible.

Then provide the Push method in the Activity:

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

This completes the basic migration, you can open a new Scene page directly in this Activity.

Issues

Dialog

A normal Dialog's Window is independent and in front of the Activity's Window, so if try to push a Scene in a opening Dialog, it will cause the Scene to appear behind it. You can close the dialog box when click, or use Scene to implement the dialog instead of a system Dialog.

SurfaceView and TextureView

When the Scene is popping, the animation will be executed after the Scene life cycle is executed. However, if there is a SurfaceView or a TextureView, this process will cause the SurfaceView/TextureView to turn to black.

You can get and re-assign the Surface before the animation end to avoid issues on TextureView, and capture the last bitmap and set to a ImageView to avoid issues on SurfaceView.

Status Bar related

There is no official API of notch screen before Android P, and each vendor has its own implementation.

If you try to hide the status bar with WindowFlag or View's UiVisibility, it will trigger the re-layout of the entire Activity.

This may causes the layout change of the Scene inside, and the behaviors may be not as expected in some cases.

License

Copyright (c) 2019 ByteDance Inc

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

scene's People

Contributors

qii avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

scene's Issues

如何向 Scene 传输数据?

Activity 有一个 Object 要传给 Scene,Scene支持构造函数吗,如果是View的话应该是可以交给setter的才对

通过setupWithFragment创建的scene如何获取activity绑定的的NavigationScene

因为是改造的旧项目。所以会有fragment和activity的两种迁移方式.

MainActivity--  NavigationSceneUtility.setupWithActivity -- EmptyholderScene
   |
  viewpager -- |
           Homefragment  -- GroupSceneUtility.setupWithFragment -- HomeScene 
           other fragments

我在HomeScene 中点击并想要从MainActivity的NavigationScene push 一个scene, 请问怎么才能从HomeScene 获取MainActivity绑定的NavigationScene?

Scene Event/Router

  • 首先表示感谢,从这个项目中学到了很多
  • 目前正在调研是否可以接入公司项目(首页也是单Activity,多Fragment,bugly线上反映的Fragment问题不少),不知道后续是否会支持类似Scene-Event之类的组件来支持Scene间通信,尤其是在Group的场景下
  • 组件化的项目中,router功能不知道会不会被支持,如果有这个功能,相信会有非常多的人想去尝试的!

请教一个关于PushResultCallback的问题

项目是模块化开发的,之前在传递一个实体类的时候很顺利,但是现在传递Boolean和String,在pushResultCallback中可以收到回调,但result始终为空.
image

我仔细地查找了和有效代码不同的地方,只有这一点,就是回传的实体类是实现了Serializable的,而之后两次使用传递的则是String和Boolean
求解~~~

Demo 随意点击 NullPointerException

--------- beginning of crash
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.bytedance.scenedemo, PID: 27054
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.bytedance.scene.navigation.NavigationScene.remove(com.bytedance.scene.Scene)' on a null object reference
at com.bytedance.scenedemo.navigation.remove.RemoveDemoScene$1$1.run(RemoveDemoScene.java:46)
at android.os.Handler.handleCallback(Handler.java:900)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:219)
at android.app.ActivityThread.main(ActivityThread.java:8349)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)

scene的功能特点

针对特有的功能,麻烦作者详细使用方法,并且对于java的支持,还没转kotlin。

是否应该添加一个 SceneFragment

一些特殊情况需要在已有 Fragment 中添加 Scene,我应该怎么做?使用 setupWithFragment 注册后怎么解决返回多层 Scene 问题?

所以有没有像 SceneActivity 一样的封装好的 Fragment 基类供使用

GroupScene与ViewPager使用报错

当前scene只有viewpager,且不设置viewpager的id,会报错


onCreateView(): ViewGroup = ViewPager(container.context)

//报错
 java.lang.IllegalArgumentException:  -1 view not found
        at com.bytedance.scene.group.GroupScene.findContainerById(GroupScene.java:321)
        at com.bytedance.scene.group.GroupSceneManager.moveState(GroupSceneManager.java:932)

adapter已设置

添加一个从父view逐级搜索到第一个scene的 方法

感谢作者开源的框架。已经集成进项目中,不过我是对activity的某部分的viewgroup做了scene改造。
由于需要手动在activity中需要设置NavigationScene?引用比较丑。希望增加一个从父view逐级搜索到第一个scene就返回的方法.我参考的ViewUtility的方法写的代码

类似的代码

 @Nullable
    public static Scene searchSceneFromView(@Nullable View view) {
        if (view != null) {
            Scene scene = (Scene) view.getTag(R.id.bytedance_scene_view_scene_tag);
            if (scene != null) return scene;
            if (view instanceof ViewGroup) {
                ViewGroup vg = (ViewGroup) view;
                for (int i = 0; i < vg.getChildCount(); i++) {
                    View child = vg.getChildAt(i);
                    scene = searchSceneFromView(child);
                    if (scene != null) return scene;

                }
            }
        }
        return null;
    }

Deep linking?

Is there deep linking available?
When it's will ready and how can I use that?

I cooding android side of a social network and I need handle deep link to open profiles, media and other items in the app by link

软键盘问题

请教一下,按照Demo中的示例,在有输入框的页面确实是这么做的
image
但是好像并没有生效...
image
image
请问是否别的地方也需要配置呢?比如说Manifest文件?我配置的为android:windowSoftInputMode="adjustResize"

DialogScene的写法仿照,但是背景无法实现半透明

image
最关键的在于,给onCreateView返回的View或者onViewCreated的View设置一层半透明的背景色,对吗,是这么写的,但是不太好用...
此为Demo中的DialogScene实现思路:
`public class DemoDialogWithDimScene extends Scene {
@nonnull
@OverRide
public View onCreateView(@nonnull LayoutInflater inflater, @nullable ViewGroup container, @nullable Bundle savedInstanceState) {
FrameLayout layout = new FrameLayout(requireSceneContext());
layout.setBackgroundColor(Color.parseColor("#99000000"));

    TextView textView = new TextView(getActivity());
    textView.setText(getNavigationScene().getStackHistory());
    textView.setBackgroundColor(ColorUtil.getMaterialColor(getResources(), 1));
    FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(600, 600);
    layoutParams.gravity = Gravity.CENTER;

    layout.addView(textView, layoutParams);

    layout.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            requireNavigationScene().pop();
        }
    });

    return layout;
}

}下面是我的仿照思路:class VoucherScene : BaseViewModelScene() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup,
savedInstanceState: Bundle?
): View {
val layout = FrameLayout(sceneContext!!)
layout.setBackgroundColor(Color.parseColor("#99000000"))
val layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
layoutParams.gravity = Gravity.CENTER
val child = inflater.inflate(getLayoutId(), null)
layout.addView(child, layoutParams)
return layout
}
}`

结合类似Glide这类自己绑定生命周期的如何使用?

比如:Glide这种带有什么周期感知的,自动暂停等,但是只支持view、activity、fragment这些,那么要如何配合Scene使用呢?如何传入activity的话,那么生命周期就跟随activity,也无关scene ,那就没有意义了

SceneContainerActivity透明主题

您好,我试图在应用中调用
new SceneNavigator(mTvMsg.getContext(), R.style.TranslucentActivity) .startScene(TranslateScene.class,bundle1);
主题R.style.TranslucentActivity内容如下

<style name="TranslucentActivity" parent="BaseTranslucentActivity"> @android:color/transparent @null true @android:style/Animation true @null </style>

经测试这个主题是有效的,但是启动SceneContainerActivity后效果如下
image
(请无视白边 电脑截图不是那么精准
好像设置的透明主题没有生效...

共享元素动画时长被硬编码

共享元素动画时长被硬编码为 2500 ms,没找到接口修改,希望可以开放这个设置。
我改为 300 ms 之后发现入场的动画会有卡顿的现象,请教下我可以尝试做哪些优化?

SceneInstanceUtility可见性问题

根据文档 Migration to Scene,用SceneInstanceUtility类在不同的包下显示
SceneInstanceUtility can only be called from within the same library group (groupId=com.bytedance.scene)

Why not update to androidx

I see androidx branch, but why not applied that to master, I using androidx branch and don't see any bugs until now

Software rendering doesn't support hardware bitmaps

一个比较奇怪的 Bug,第一次 push "BlurScene" 时从这个 Scene 的 onViewCreated 中执行 activity.window.decorView.draw(canvas) 没有出现任何问题,但当我 pop 掉这个 "BlurScene" 再重新 push 后就崩溃了

Why not using material components?

I see you written xml templates in scene-ui by using linear layout and a custom root layout based on it

Why not using material library components in androidx branch like coordinator layout to easy access status bar and navigation bar
Or others like appbar, material toolbar, linear layout compat and also for bottom navigation and scene content can use coordinator behaviors

I currently used edited xml&java to fill my needs, but the codes not follow project codebase so I can't make PR

And one thing more, merge master to androidx if possible

请教一下点击穿透的问题

image
参照SceneDemo中用Scene实现Dialog的例子写的提醒弹窗,但会出现点击穿透,不仅是Dialog外侧半透明区域,Dialog的View本身也可以被穿透,所以会不断启动新的Scene,(Scene真的非常优秀,看了一下启动几十个,内存也没有迅速飙升),想请教一下有什么好的解决办法...

SurfaceView 闪屏问题

项目中有一个页面使用到了 SurfaceView, 但是发现在这个页面中使用 scene 弹窗的方法时 SurfaceView 会闪屏一下.怎样优化比较好呢?

need release resources on OnDestroyView?

is I need to release resources for my views in every scene after onDestoryView called for example If I have an imageView, called setImageDrawable to null or if I using Picasso, call cancel method for Picasso? did I need something like this?

MainActivity使用delegate 点击穿透的问题

你好,我参考西瓜视频首页迁移方案,出现点击穿透的问题。
另一个是,可以更新下文档和demo吧,感觉demo中用的都是过时的方法,比如setupWithActivity,我看现在不都是用build了么。

关于拦截Pop动作的问题

项目结构是主页BottomNavigationView配合几个Scene切换,所以按照Demo中的拦截Pop页面加入了
image

但是在这个页面同级的其他Scene中也会响应该返回事件

不好的命名

不建议用常用英文单词,对搜索很不友好
错误典型:google把他们的orm库命名为room,给开发者交流带来很多麻烦

Viewpager2 adapter

Did you have any plan to implementation viewpager2 or in general recycler adapter for scene?

关于软键盘的思考

很高兴发现这个项目,我们的项目也是完全基于单Activity模式的,UI框架也是叫[Scene],由我独立开发维护,很多核心**也和这个项目接近,目前暂时没有开源。在我们探索的过程中发现如果弹窗(基于Scene)需要软键盘输入就会导致底下的Scene变形,原因是Scene实际是基于View的,所有View都是在同一Window上操作的,而软键盘是直接操作Window。所以当软键盘弹出的时候也许UI框架需要做一个软键盘导致的View layout,measure 事件的特殊处理,相当于软键盘弹出事件分发机制。您觉得软键盘应该怎么处理呢?

使用说明

可以加一个Scene的生命周期列举图吗

Kotlin直接取用控件id

image
Kotlin支持的直接调用控件id不可用,因为只对Activity、Fragment或Dialog适用..
想请教一下有什么好的解决办法嘛

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.