Android的Material Design Motion

One of the main features in Material Design is the transition of elements and components to express relationships between them or outcomes and availability for actions.

材料设计的主要功能之一是元素和组件之间的过渡,以表达它们之间的关系或结果与操作的可用性。

Since 1.2.0-alpha05 version, Material Components for Android library has incorporated Transitions and Motion. They are an easy-to-use set of classes to implement different type of customizable transitions and animations.

从1.2.0-alpha05版本开始, Android库的Material Components已合并了Transitions和Motion。 它们是一组易于使用的类,用于实现不同类型的可自定义过渡和动画。

There are different transition patterns that comprised the Material Design motion system for transitioning between components or full-screen views.

材料设计运动系统由不同的过渡模式组成,用于在零部件或全屏视图之间过渡。

What’s really important is choosing which transition pattern is appropriate for each use case.

真正重要的是选择适合每个用例的过渡模式。

The transition patterns are:

过渡模式为:

  • Container transform: It’s used in transitions that involve a persistent element such as a list, card surface or button.

    容器转换:用于涉及持久性元素(例如列表,卡片表面或按钮)的转换。

  • Shared axis: It’s used for transitions between UI elements that have a spatial or navigational relationship.

    共享轴:用于具有空间或导航关系的UI元素之间的过渡。
  • Fade through: When a relationship between elements is insignificant or does not exist.

    淡入淡出:元素之间的关系不明显或不存在时。
  • Fade: It’s is applied in the UI elements that need to enter or exit the screen.

    淡入淡出:在需要进入或退出屏幕的UI元素中应用。

Recently, I’ve been working on some samples that use Material Design motion system.

最近,我一直在研究一些使用Material Design运动系统的示例。

implementation('com.google.android.material:material:1.2.0-beta01')

容器变换 (Container Transform)

This pattern is used to create a visible connection between two UI elements. It transforms one element into another. This is a common UX pattern to express that one element is related with another as item-detail container. For instance, if a card item in a list transforms into a detail view, the user perceives that the detail page is an extended version of the card.

此模式用于在两个UI元素之间创建可见的连接。 它将一个元素转换为另一个元素。 这是一种常见的UX模式,用于表示一个元素与另一个元素相关联,作为项详细信息容器。 例如,如果列表中的卡片项目转换为详细信息视图,则用户会认为详细信息页面是卡片的扩展版本。

This could be also used as a transformation of a FAB button into a menu or a sheet.

这也可以用作将FAB按钮转换为菜单或工作表的方式。

This transition can be applied between activities, fragments or views, depending on whether we want to transform a view of one activity or fragment in another activity, fragment or view.

可以在活动,片段或视图之间应用此过渡,具体取决于我们是否要在另一个活动,片段或视图中转换一个活动或片段的视图。

This transformation is fully customizable by specifying different values for properties that affect the transition.

通过为影响过渡的属性指定不同的值,可以完全自定义此变换。

  • duration

    持续时间

Sets the duration of this transition in milliseconds.

设置此过渡的持续时间(以毫秒为单位)。

  • interpolator

    内插器

Sets the interpolator of this transition. We can specify some interpolator like FastOutSlowIn or custom using PathInterpolator for a cubic Bezier curve.

设置此过渡的插值器。 我们可以指定一些插值器,例如FastOutSlowIn或使用PathInterpolator自定义三次贝塞尔曲线。

  • fadeMode

    fadeMode

Sets the fade mode to be used to switch the content of the start view with that of the end view. There are four fade modes:

设置淡入淡出模式,用于将开始视图的内容与结束视图的内容切换。 有四种淡入淡出模式:

- FADE_MODE_IN: Fade the incoming content without change the opacity of outgoing content. This is the default mode.

FADE_MODE_IN :淡入传入内容,而不更改传出内容的不透明度。 这是默认模式。

- FADE_MODE_OUT: Fade the outgoing content without change the opacity of incoming content.

FADE_MODE_OUT :淡出输出内容而不更改输入内容的不透明度。

- FADE_MODE_CROSS: Cross-fade the incoming and outgoing content.

FADE_MODE_CROSS :淡入淡出传入的内容。

- FADE_MODE_THROUGH: Sequentially fade out the outgoing content and fade in the incoming content.

FADE_MODE_THROUGHFADE_MODE_THROUGH淡出输出内容并淡入输入内容。

  • fitMode

    fitMode

There are three options:

共有三个选项:

- FIT_MODE_HEIGHT: Fit the incoming content to the height of the outgoing content during the scale animation.

FIT_MODE_HEIGHT :在缩放动画期间,将传入内容调整为传出内容的高度。

- FIT_MODE_WIDTH: Fit the incoming content to the width of the outgoing content during the scale animation.

FIT_MODE_WIDTH :在缩放动画过程中,使传入内容适合传出内容的宽度。

- FIT_MODE_AUTO: Use FIT_MODE_HEIGHT or FIT_MODE_WIDTH automatically.

FIT_MODE_AUTO :自动使用FIT_MODE_HEIGHT或FIT_MODE_WIDTH。

  • containerColor

    containerColor

Sets the background color of the morphing container. This color is drawn below the start and end views. This is very useful when one or both do not have a solid color background. This can be also used to set the color of transition to enhance the transformation from one view into another.

设置变形容器的背景颜色。 此颜色绘制在开始视图和结束视图下方。 当一个或两个都不具有纯色背景时,这非常有用。 这也可以用来设置过渡的颜色,以增强从一种视图到另一种视图的转化。

  • scrimColor

    scrimColor

Sets the color to be drawn under the morphing container within bounds of the drawingView.

设置要在drawingView范围内的变形容器下绘制的颜色。

The drawingView is the view to which the transition will overlap. This drawingView can be specified using the setDrawingViewId() function.

drawingView是过渡将与之重叠的视图。 可以使用setDrawingViewId setDrawingViewId()函数指定此drawingView。

private fun buildContainerTransform() =
        MaterialContainerTransform().apply {
            addTarget(binding.coordinator)
            duration = 500
            fadeMode = MaterialContainerTransform.FADE_MODE_IN
            interpolator = FastOutSlowInInterpolator()
        }

FAB到菜单 (FAB to Menu)

Image for post

This transition transforms a FAB into a menu. We will specify which is the start and end view.

此转换将FAB转换为菜单。 我们将指定哪个是开始视图和结束视图。

private fun buildContainerTransformation() =
        MaterialContainerTransform().apply {
            scrimColor = Color.TRANSPARENT
            duration = 300
            interpolator = FastOutSlowInInterpolator()
            fadeMode = MaterialContainerTransform.FADE_MODE_IN
        }           




    private fun setClickListeners() {
        binding.floatingActionButton.setOnClickListener {
            val transition = buildContainerTransformation()


            transition.startView = binding.floatingActionButton
            transition.endView = binding.card


            transition.addTarget(binding.card)


            TransitionManager.beginDelayedTransition(findViewById(android.R.id.content), transition)
            binding.card.visibility = View.VISIBLE
            binding.fabScrim.visibility = View.VISIBLE


            binding.floatingActionButton.visibility = View.INVISIBLE
        }
    }

FAB到活动 (FAB to Activity)

This transition transforms a FAB into an Activity. It uses the MaterialArcMotion to move the container along a curve.

此转换将FAB转换为活动。 它使用MaterialArcMotion沿曲线移动容器。

Image for post
Left: with MaterialArcMotion() — Right: without MaterialArcMotion()
左:使用MaterialArcMotion()—右:不使用MaterialArcMotion()
private fun buildContainerTransform() =
        MaterialContainerTransform().apply {
            addTarget(binding.coordinator)
            setAllContainerColors(MaterialColors.getColor(binding.root, R.attr.colorSurface))
            pathMotion = MaterialArcMotion()
            duration = 500
            interpolator = FastOutSlowInInterpolator()
            fadeMode = MaterialContainerTransform.FADE_MODE_IN
        }
Image for post

MaterialCard查看活动 (MaterialCardView to Activity)

Transform a list item into an Activity. We can observe the difference between FADE_MODE_IN and FADE_MODE_OUT.

将列表项转换为活动。 我们可以观察到FADE_MODE_INFADE_MODE_OUT之间的区别。

Image for post
Left: FADE_MODE_OUT — Right: FADE_MODE_IN
左:FADE_MODE_OUT —右:FADE_MODE_IN
inner class ViewHolder(val binding: ItemNoteBinding) : RecyclerView.ViewHolder(binding.root) {
        fun bind(note: Note) {
            binding.note = note
            binding.noteCard.transitionName = note.id.toString()
            binding.noteCard.setOnClickListener {
                noteClickListener.onNoteClick(note.id, binding.noteCard)
            }
        }
    }
val adapter = NotesAdapter(notes)
        adapter.noteClickListener = object : NotesAdapter.NoteClickListener {
            override fun onNoteClick(id: Int, noteCard: MaterialCardView) {
                val intent = Intent(this@NotesActivity, NoteDetailActivity::class.java)
                val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
                    this@NotesActivity, noteCard, id.toString()
                )
                intent.putExtra("noteId", id)
                startActivity(intent, options.toBundle())
            }
        }
class NoteDetailActivity : AppCompatActivity() {
    private lateinit var binding: NoteDetailActivityBinding


    override fun onCreate(savedInstanceState: Bundle?) {
        window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
        binding = NoteDetailActivityBinding.inflate(layoutInflater)
        val noteId = intent.getIntExtra("noteId", 0)
        val note = notes.find { it.id == noteId }
        binding.note = note
        binding.coordinator.transitionName = noteId.toString()
        setEnterSharedElementCallback(MaterialContainerTransformSharedElementCallback())
        window.sharedElementEnterTransition = buildContainerTransform()
        window.sharedElementReturnTransition = buildContainerTransform()
        setContentView(binding.root)
        super.onCreate(savedInstanceState)
    }


    private fun buildContainerTransform() =
        MaterialContainerTransform().apply {
            addTarget(binding.coordinator)
            duration = 300
            interpolator = FastOutSlowInInterpolator()
            fadeMode = MaterialContainerTransform.FADE_MODE_IN
        }
}

Android导航组件中的容器转换 (Container Transform in Android Navigation Component)

val adapter = AlbumsAdapter(albums, requireContext())
        adapter.albumClickListener = object : AlbumsAdapter.AlbumClickListener {
            override fun onAlbumClick(id: Int, cardView: MaterialCardView) {
                val extras = FragmentNavigatorExtras(
                    cardView to id.toString()
                )
                val action = AlbumsFragmentDirections.navToAlbumFragment(id)
                findNavController().navigate(action, extras)
            }
        }
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        sharedElementEnterTransition = buildContainerTransform()
        sharedElementReturnTransition = buildContainerTransform()
    }


    private fun buildContainerTransform() =
        MaterialContainerTransform().apply {
            drawingViewId = R.id.nav_host_fragment
            interpolator = FastOutSlowInInterpolator()
            containerColor = Color.WHITE
            fadeMode = MaterialContainerTransform.FADE_MODE_OUT
            duration = 300
        }
Image for post

共享轴 (Shared Axis)

This pattern is used for transitions between UI elements that have a spatial or navigational relationship. It uses a transformation on the x, y, or z axis to reinforce the relationship between elements. By moving in the same direction, elements are perceived to be related to each other.

此模式用于具有空间或导航关系的UI元素之间的过渡。 它使用x,y或z轴上的变换来增强元素之间的关系。 通过沿相同方向移动,可以将元素视为相互关联。

val forward = true
                val fragment = MyFragment.newInstance()
                // axis: MaterialSharedAxis.X, Y or Z
                // forward: true if it move in the forward direction or false if it move in the backward direction
                fragment.enterTransition = MaterialSharedAxis(MaterialSharedAxis.Y, forward)
                supportFragmentManager
                    .beginTransaction()
                    .replace(R.id.fragment_container, fragment)
                    .commit()

X轴 (X-axis)

Image for post

An example of using MaterialSharedAxis transition on the X-axis for an application walkthrough.

在X轴上使用MaterialSharedAxis过渡进行应用程序遍历的示例。

Y轴 (Y-axis)

Image for post

A vertical stepper using MaterialSharedAxis transition on the Y-axis.

在Y轴上使用MaterialSharedAxis过渡的垂直步进器。

Z轴 (Z-axis)

Z-axis transitions indicate moving one level upward or downward in an app’s hierarchy.

Z轴过渡指示在应用程序的层次结构中向上或向下移动一个级别。

Image for post

淡入淡出 (Fade through)

This pattern is used for transitions between UI elements that do not have a strong relationship to each other.

此模式用于在彼此之间没有密切关系的UI元素之间的过渡。

The fade through is the best choice in a bottom navigation view because destinations are often grouped into major tasks that may not relate to one another.

在目的地导航视图中,淡入淡出是最佳选择,因为目的地通常被分组为可能彼此不相关的主要任务。

class ArtistsFragment : Fragment() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enterTransition = MaterialFadeThrough()
    }
  
    ...
}
Image for post

褪色 (Fade)

This pattern is used for UI elements that enter or exit within the bounds of the screen, such as a dialog that fades in and out of view from the center.

此模式用于在屏幕范围内进入或退出的UI元素,例如从中心淡入或淡出对话框的对话框。

// import androidx.transition.TransitionManager        
        
        binding.floatingActionButton.post {
            val transition = MaterialFade().apply {
                duration = 1500
            }
            TransitionManager.beginDelayedTransition(binding.root, transition)
            binding.floatingActionButton.visibility = View.VISIBLE
        }
Image for post

文档和帮助 (Documentation and help)

翻译自: https://proandroiddev.com/material-design-motion-for-android-396da62edb1c

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值