当前位置:网站首页>"Remake Apple product UI with Android" (2) -- silky Appstore card transition animation
"Remake Apple product UI with Android" (2) -- silky Appstore card transition animation
2022-07-03 15:46:00 【Code is not difficult to write】
Preface
I've always wanted to take the time to learn Apple The original of the product UI And animation , Super silky .
today , The goal is AppStore The card flow of the home page and its transition animation .
It should be noted that , If from static layout 、 Dynamic switching effect ( Animation function curve 、 blurred )、 The details are presented to evaluate the results of this reprint , This article only implements the most important part , There is considerable room for optimization in the future .
AppStore And Android Preview the effect
( Video to GIF The pixel compression is severe , Please forgive me )
- AppStore Official card switching effect :
One word , Silky ; And the animation of closing the card detail page can be interrupted by touch operation .
- This article uses Android Re engraved card switching effect :
The final implementation does not include the function of sliding on the left to return to the previous page , And there are still a lot of details that can be optimized , There's a long way to go .
1. Page content analysis
Before the start , We might as well take a closer look at the information covered on this page , Then convert it into our business needs , Organize your thoughts in advance and then start writing .
We watched , Pick out the basic implementation ideas piecemeal , From now on, I will gradually mention some Android key word .
1.1 Static layout
The pictures above are AppStore Home page 、 Card details page
Let's first look at what the static layout covers , Whole AppStore In fact, the home page is mainly composed of two pages :
- home page
- The page content : A card stream of cards of the same size , Each card contains the basic information of this page ( Main subtitle 、 Abstract 、 Background map )
- Card style requirements : Shadows around 、 Card fillet 、 Show the background picture 、 Content expansion ( Add text later )
We naturally thought that we could use CardView
To fulfill this need , Shadows can be made with the help of elevation
To set , Rounded corners can be used cornerRadius
, Show the background image and expand the content by adding LinearLayout
and ScrollView
To achieve . Um. , Very suitable .
Besides , Card flow can be realized by RecyclerView
To carry , every last ViewHolder
They all have one card
, We go through ArrayList To store the titles of all cards 、 Abstract 、 Background map ID, In this way, the card flow can be realized .
- Card details page
- The page content : Reuse All the elements of the front page card , And unfold the card , Added the text in . Besides , One is fixed in the upper right corner 、 Not follow ScrollView Changed page close button .
In terms of visual effect , The details page is just a copy of the card , But added a body part ; From an implementation perspective , We also use one CardView
As the basis of the details page , Add one of them ScrollView As the carrier of the text . This will facilitate our follow-up Shared element animation .
After reading the static page , Let's sort out the ideas :
- First , We create the basic style of the card , We named it _article_card_layout.xml_
- next , We're going to have two
Fragment
, among ,_HomeFragment Card stream for home page ,DetailFragment_ Card flow for detail page . - HomeFragment It covers a RecyclerView, Its ViewHolder Medium itemView, That's what we created above article_card_layout.
- _DetailFragment_ Will be our Constantly reusing objects , We set the of each card Click to listen for events , In each When the card is clicked , We have confirmed the contents of all elements of the details page that will pop up , Load the data in as soon as possible , And render the animation 、 Open this new page .
The overall structure is shown in the figure below :
1.2 Page switching dynamic effect
Let's start with slow down 5 Times AppStore Animation effect of card opening :
On the whole , It's like the lower end of a card is slowly stretched out , Jump out in front of us . ad locum , Let's take a closer look at , What do we need to deal with in this animation :
- Shared elements : The background in the card 、 The main and sub headings should naturally transition to the details page ; This requires our help Shared element animation . Detailed room Link: Use transitions to animate layout changes | Android developer | Android Developers (google.cn)
- Card size and outline : The card is clicked / The moment of touch will shrink first , Then the pop-up , The visual effect of the overall animation is like a spring , We can use Android Self contained Animation interpolator OverShootInterpolator To realize the animation curve shaped like a spring ; We use... In shared element animation
<changeBound>
And<changeTransform>
To achieve card size 、 Changes in contour . - The fillet of the card Corner: Card Corner Will gradually decrease to 0, This needs to be realized by ourselves .
- Blurring effect of other cards on the home page : After clicking on the card , Other elements of the home page will gradually blur , To highlight the main body .
2. Page implementation
The thought is finished , Let's write . In order to ensure the readability of the article , The code here will only put the core part , Students who really need the code can get it at the end of the article .
We will follow the train of thought sorted out in the previous article , Step by step .
2.1 Card stream & Static layout of card detail page
- First , Create our cards (article_card_layout.xml), As mentioned earlier , We will use CardView As a basic carrier
- Create a CardView:
- default elevation=2 Helped us achieve the shadow
- Set up cardCornerRadius=14dp, Realize the fillet effect of the card
- stay CardView Create a... Inside LinearLayout
- Create three... Inside it TextView, Used to carry the main and sub headings and abstract respectively
- Put this LinearLayout Of backGround As a container for our background image , Let's put a default in first .
thus , What we have xml The structure and its preview effect are as follows :
- establish _HomeFragment_, Deal with the most important RecyclerView
- We created RecyclerView The required Adapter And ViewHolder
- Let's create a data class first ,ArticleCardData, Used to store the text content and background image of each card ID; Of course , You can also put any content you want the card to be customized easily .
data class ArticleCardData(
val backGroundImage: Int = R.drawable.testimg,
val cardTitle: String = "Latest",
val mainTitle: String = "Extraordinarily,\nundefeated.",
val rootText: String = "i-Sense makes life better.",
val contentText: String = "",
val mainTitleColor: Int = Color.parseColor("#fafdfb")
)
We need to ViewHolder Every time a binding is executed (onBindViewHolder) When , Put the main and sub headings of the article 、 The background is loaded
initialization RecyclerView, Set up adpater,layoutManager etc. .
ad locum , It should be noted that ,RecyclerView in , If you want to achieve every Item Up, down, left and right spacing of , We need to create one ourselves ItemDecoration Class item Put in , To achieve the spacing effect .
class CardItemDecoration : RecyclerView.ItemDecoration() {
private val itemSpaceDistance = 24f.dp.toInt()
private val horizontalSpace = 18f.dp.toInt()
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
super.getItemOffsets(outRect, view, parent, state)
outRect.apply {
this.left = horizontalSpace
this.right = horizontalSpace
this.bottom = itemSpaceDistance
}
if (parent.getChildAdapterPosition(view) == 0) {
outRect.top = itemSpaceDistance
}
}
}
- Create a click event for each card , Jump to DetailFragment, And load the data corresponding to the card :
here , I use ViewModel To achieve Fragment Data transfer between : take ViewModel Of Provider Set to Activity, So our ViewModel The life cycle follows Activity change , So as to help us realize data transmission .
- initialization ViewModel, Let its life cycle follow activity go
// We are HomeFragment.kt
articleCardViewModel = ViewModelProvider(activity).get(ArticleDetailViewModel::class.java)
- In this activity Whatever is inside fragment Inside , In the same way , Access to this viewModel
// We are DetailFragment.kt
viewModel = ViewModelProvider(activity!!).get(ArticleDetailViewModel::class.java)
- Card click events : The current card is to viewModel Pass in the value of this card , Then by DetailFragment receive , It can get these values when rendering its own page , And became the detail page of that card .
// to recyclerView Each Item Add click event
override fun onItemClick(viewHolder: RecyclerView.ViewHolder?) {
var position = cardRecyclerView.getChildLayoutPosition(viewHolder!!.itemView)
GlobalScope.launch(Dispatchers.Default) {
// Update the main subtitle 、 Abstract, etc
articleDetailViewModel.articleCardData = cardArray[position]
// Update background picture
articleDetailViewModel.updateBackGroundImage(resources, activity!!)
// In the current item The location of ,position
articleDetailViewModel.position = position.toString()
}
// Use Navigation Jump to the next page .
}
DetailFragment The layout is in _article_detail_layout.xml_ On the basis of , A layer has been added to the outside ScrollView To show the longer text , And added contentText Of TextView, The overall structure and preview are as follows :
)
DetailFragment receive data , And render your own picture :
//in DetailFragment.kt
//viewModel Card related data passed in
viewModel.articleCardData.apply {
view.findViewById<TextView>(R.id.mainTitle).text = this.mainTitle
view.findViewById<TextView>(R.id.cardTitle).text = this.cardTitle
view.findViewById<TextView>(R.id.rootText).text = this.rootText
view.findViewById<TextView>(R.id.mainTitle).setTextColor(this.mainTitleColor)
// Set the text
if (this.contentText != "") {
view.findViewById<TextView>(R.id.contentText).text = this.contentText
}
// Setting the background
view.findViewById<LinearLayout>(R.id.cardLinearLayout).background = viewModel.backGroundImage
}
view.findViewById<CardView>(R.id.backGroundCard).transitionName = "backGroundCard${viewModel.position}"
- thus , The static page layout is finished . Last , Then sort out the process in the form of pictures !
2.2 Transition animation between card and detail page
Finally came to the most interesting part , In this link, we invite the most core role :SharedElementTransition Shared element animation
Introduction to the use of shared element animation
For the official introduction of shared element animation, please go to : Use transitions to animate layout changes | Android developer | Android Developers (google.cn)
Attached is a more widely used shared element animation library :Material-Motion
here , Let me introduce... In my own way :
- Shared element animation can be used for both Fragment between , It can also be used for Activity between , It's quite convenient to use , You only need to ensure that the shared elements are in two Fragment Of TransitionName Agreement , And bind it before jumping .
- In this switching process , We can designate a Transition Animation to achieve the effect we want , such as Fade() Can gradually come in and out ,ChangeTransform() Realize dimensional change .
- Transition The bottom layer of animation is attribute animation , He will get FragmentA A value of a shared element in As a starting point , For example, location x=0,y=0, And then get FragmentB The location of shared elements in x=100,y=100 As a destination , Then perform an attribute animation , To make this shared element move smoothly past .
- I know the principle , We can easily customize Transition, Just rewrite a few methods , Control the values of the start and end points we need , Just redefine the attribute animation we want . See the official documents for details : Create custom transition animation | Android developer | Android Developers (google.cn)
stay RecyclerView in , Give Way Item Animate as a shared element
We mentioned above , If you want to perform attribute animation , Is to let two Fragment Shared elements of have the same TransitionName, stay RecycerView in , We do this :
- When creating these card streams , We give Of each card TransitionName The assignment is "shared_card${position}",position Make it rank , To ensure their TransitionName It's unique .
- next , After the card is clicked , to DetailFragment Pass in the currently clicked card TransitionName, And let DetailFragment Modify your own card component TransitionName by "shared_card${position}"
such , We implement the binding .
next , Is to let everyone Item Add a click event Navigation Jump !( You can also use it FragmentManager):
a. We need to first create a current View Corresponding to TransitionName The binding of ( The naming rules mentioned above )
// First create a binding , The form is view to TransitionName
val extras = FragmentNavigatorExtras(
viewHolder.itemView.findViewById<CardView>(R.id.backGroundCardView) to "backGroundCard${position}",
)
b. then , We use navigate() Realize jump , Inside the function, we fill in the target fragment ID With previously bound _extras_
view!!.findNavController().navigate(
R.id.action_to_article, null,
null,
extras
)
Complete the last step of the shared element animation , stay _DetailFragment_( The goal is Fragment) Set what we need Transition effect . sharedElementEnterTransition The object accepts a Transition class ,Transition It includes the animation effects we need to achieve . Here we use R.transiton.shared Is custom Transition aggregate .
//in DetailFragment.kt
sharedElementEnterTransition = TransitionInflater.from(requireContext()).inflateTransition(R.transition.shared)
sharedElementReturnTransition = TransitionInflater.from(requireContext()).inflateTransition(R.transition.shared)
The shared element animation we use Transition:R.transition.shared
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:transitionOrdering="together"
android:duration="400">
<transitionSet android:transitionOrdering="together">
<transition class="isense.com.ui.myTransition.MyCornerTransition">
</transition>
</transitionSet>
<changeBounds android:interpolator="@anim/my_overshoot">
</changeBounds>
<changeTransform android:interpolator="@anim/my_overshoot">
</changeTransform>
</transitionSet>
In the above code , We define Transition It includes three contents , Namely :changeBounds, CornerTransiton( Self defined ) and changeTransform. We use them to achieve the required card expansion effect .
Why use OverShootInterpolator?
Mentioned earlier ,AppStore The original animation function curve is spring like , This is related to OverShootInterpolator The function curve of is similar :
They will all reach the target value , Continue to take a small step forward , Then go back , Just like the function curve below : f(t)=t∗t∗((1.2+1)∗t+1.2)+1.0f(t) = t * t * ((1.2 + 1) * t + 1.2) + 1.0f(t)=t∗t∗((1.2+1)∗t+1.2)+1.0
How to realize the fuzziness of other cards ?
here , I've got the help of Github Open source library :wasabeef/Blurry: Blurry is an easy blur library for Android (github.com)
It can realize the current context The picture turns blurred , And remap back to rootViewGroup.
viewHolder.itemView.visibility=View.INVISIBLE
Blurry.with(context).radius(25).sampling(1).animate(100).onto(NoiseConstraintLayout)
viewHolder.itemView.visibility=View.VISIBLE
Last , To ensure the effect when the shared animation returns , Please note that :
In order to ensure DetailFragment return HomeFragment Can also have the effect of sharing animation , Please be sure to in HomeFragment Of onCreate() Add the following code :
postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }
If you find it interesting , You can click the link below to browse more similar articles :
“ use Android Repeated engraving Apple product UI”(3)— Elegant statistical charts - Nuggets (juejin.cn)
“ use Android Repeated engraving Apple product UI”(1)— Silky noise monitoring volume bar - Nuggets (juejin.cn)
At the end
In the field of Technology , There's no course you can take once and for all , No matter how good the course is, it can only be “ Master leads in , Cultivation depends on individuals ”.“ knowledge has no limit ” this sentence , In any field of Technology , It's not just good habits , What's more, programmers and engineers are not eliminated by the times 、 A necessary prerequisite for better opportunities and development .
If you feel that you are inefficient in your studies , Lack of proper guidance , You can leave a message or a private message in the comment area , Join us with rich resources , Let's learn from the technology circle with strong learning atmosphere !
Join us ! There are a lot of technical bulls from the front line in the group , There are also farmers who struggle in small factories or outsourcing companies , We are committed to building an equality , High quality Android Communication circle , It doesn't have to take everyone's technology by leaps and bounds in the short term , But in the long run , Vision , pattern , The direction of long-term development is the most important .
35 Middle aged crisis is mostly caused by short-term interests , The value is squeezed out too early , If you can set up a correct long-term career plan from the beginning .35 You will only be worth more than the people around you .
边栏推荐
- Tensorflow realizes verification code recognition (III)
- Tensorflow realizes verification code recognition (I)
- Popular understanding of linear regression (I)
- Win10 enterprise 2016 long term service activation tutorial
- Summary of concurrent full knowledge points
- Reading notes of "micro service design" (Part 2)
- leetcode_ Power of Four
- 分布式事务(Seata) 四大模式详解
- Halcon and WinForm study section 1
- Popular understanding of gradient descent
猜你喜欢
Intelij idea efficient skills (III)
QT use qzxing to generate QR code
Find mapping relationship
Summary of JVM knowledge points
找映射关系
Tensorflow realizes verification code recognition (I)
Microservices - load balancing ribbon
Redis cache penetration, cache breakdown, cache avalanche solution
Jvm-03-runtime data area PC, stack, local method stack
nifi从入门到实战(保姆级教程)——flow
随机推荐
秒杀系统3-商品列表和商品详情
Find mapping relationship
Popular understanding of random forest
Reentrantlock usage and source code analysis
Enable multi-threaded download of chrome and edge browsers
Get the executable path through the process PID (queryfullprocessimagename)
Baidu AI Cloud helps Shizuishan upgrade the smart health care model of "Internet + elderly care services"
Atlas atlas torque gun USB communication tutorial based on mtcom
Problems of CString in multithreading
[combinatorial mathematics] binomial theorem and combinatorial identity (binomial theorem | three combinatorial identities | recursive formula 1 | recursive formula 2 | recursive formula 3 Pascal / Ya
Use percent sign in CString
秒殺系統3-商品列錶和商品詳情
Custom annotation
整形和浮点型是如何在内存中的存储
潘多拉 IOT 开发板学习(HAL 库)—— 实验5 外部中断实验(学习笔记)
Redis在Windows以及Linux系统下的安装
Calibre LVL
Detailed explanation of string function and string function with unlimited length
Go语言自学系列 | golang中的if else if语句
Microservice sentinel flow control degradation