Advanced Jetpack Compose

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
um hello everyone i think you should see me right now if you can please leave a note in the chat or something and please let me know if the quality is okay uh the image quality and if you can hear me all right before we get started we'll get started in just a few minutes i think because youtube is kind of giving me some issues saying that the the resolution is not ideal or optimal and that's the quality might might be a bit worse than i thought but uh i think it should be fine because this is kind of the settings that i use for the previous session so please please let me know if everything is okay if you can see me good uh if you can hear me okay and if so then we can get started and i'll also check this real quick and of course discord is giving me some now um okay so uh i guess if no one is complaining then everything is all right so i can't really uh change anything without any complaints uh so uh without further further ado i just head on into the presentation hey emmanuel nice to see you here um so this is our second presentation on the topic of just by compose if you haven't been here about a month or so ago we had our first presentation where we talked about the basics of jetpack compose what it is and how it works behind the scenes and some of the fundamental topics you should know to be able to use it such as what are the basic building blocks how does the rendering process work what about state what about animations everything you know what what gives you the basic information about about building any you know small apps um so right now we'll kind of go into the same topic but on to more advanced uh part of the thing so we'll talk about uh you know how to use compose in in for more complex use cases and how to handle those use cases so uh overall i have a presentation prepared i'm not sure if it should take as long as the previous one because the previous one was quite big um but thank you for joining here and to anyone who's listening currently or will be listening later on or watching the the videos after they they are processed uh thank you for being here uh and make sure to leave us any kind of comments if you want to you know uh ask anything that wasn't really clear in the presentation or just reach out to us either via our youtube channel via our social media uh which we have reach out to me personally i'll leave a few links um in the presentation just feel free to reach out and we can you know chat um so without further ado um let me kind of switch over to the presentation so you should be seeing the presentation right now um if the presentation is not really clear or anything just let me know and i'll kind of try to fix it hopefully um thank you for joining again uh this is a part of our google developers group aussie here that we have we try to have presentations every few months at least uh if we can um we haven't really had as much luck previous year because of the whole corona situation and we couldn't really find uh speakers for our presentations but we're trying to change that and we're just trying to kind of uh move into an online format and give more presentations if you have any kind of ideas that you want to um collaborate with us any kind of topics that you want to talk about and uh you know present within the gdg austin just feel free to reach out and we'll organize something so uh as i mentioned today i'll talk about the uh advanced aspects of jetpack compose uh this entails talking about you know more complex use cases uh such as using state uh handling state and using reactive state actually but this also entails something uh in the manner of using more complex animations to achieve transitions between your screens um not just that but also how to use compose to build more generic components so you can reuse them in a much better way but as i mentioned we'll talk about all this in a bit um before we do uh let me just say a few quick words about me so you can find me on many different parts of social media uh i'm currently working as you know i'm philly my name is phil bavic and i'm working as a video instructor at raceware which is the company behind riverland.com so we do a lot of educational content in terms of programming so not just android uh and ios development also unity server-side swift uh flutter as of recent uh and just there's a lot of content we have on our website that you can access uh both for free and under some certain subscriptions where you get gain access to a lot of books that a lot of people are really happy to to be reading so if you want to reach out about like our subscriptions and everything you can just feel free to reach out to me you can visit our website and learn a bit more about that um if you want to reach out to me for uh you know in terms of our personal uh you know a personal question in terms of uh development or just trying to um you know organize something with the gdg ostic or some of the other projects that i work on you can use twitter linkedin you can find me on the gd website where you can find even more resources to find me or you can join our discord that we have um which is uh publicly publicly available and there's a lot of uh folks there that uh chat every day with us uh and you can just you know discuss with us whenever you want or talk to us whenever you want uh just let me know if you can see everything correctly right now if everything is you know completely clear and the the screen is completely visible just like leave a thumbs up or something in the chat um other than those uh links where you can reach out to me and ask some questions i also hold sunday one-on-one mentoring sessions where you can ask me pretty much anything that i can give you some advice or tips on or share my experience with and those sessions are available i think we have two or three sessions every single sunday so you can just sign up and chat with me whenever you want or whenever there's a free slot i guess so i would definitely you know if you have any questions that you want a person with a bit of experience in let's say android or kotlin and you want to ask me some questions just feel free to take this opportunity because this is completely free so you don't have to worry about payment or anything um so as i mentioned i'll talk about three or four different things here i'll talk about state-based screens and how you can show or hide the ui depending on the state i'll also talk a bit about how to use um reactive architectures or structures so combining compose with uh mvvm or model view view model and also live data or flow uh depending on which one you use for your projects which one you use for your application i'll also talk a bit about transitions and how you can create more concrete and more complex animations in compose and how you can update your state and your ui depending on those transitions and finally i'll kind of dive into one of my i guess favorite topics or favorite things to talk about and this is generics and how to talk how to build generic composable components that you can not just reuse across your project or maybe even across different projects but also reuse in different types of use cases and different types of features where you have a certain type of behavior that you just want it to be completely reusable and completely generic so you don't have to worry about you know changing or copying and pasting code um instead you can use a generic function of course and then you can just have everything be reusable but a bit more about that later um so one of the things that i mentioned uh previously is that compose is all about states so in compose the ui is actually a representation of state uh some people actually say that it's a function of state which is not which is actually a bit more more appropriate so to say it's a better explanation because compose runs on just functions and all of those functions all they do is represent some states in base in terms of ui components so in that case um compose is a function of state and all you do is just based on the state you have and how the state changes and as i mentioned uh in the previous presentation um if you have some some ui components that you want to show or hide at different uh points in time then uh what you want to do is actually use if all or else statements or sorry if and else statements or when statements or conditions overall you want to use conditions which basically change the way you want to show your ui and in terms of that you then um sorry and because of the the conditions you have you might show some new components or hide some other components if you don't really uh want to show them anymore and one of the most common use cases are drawers and dialogues or any kinds of menus that you want to show that are not there the entire time they are only there when you actually need them so we'll kind of see how that works in a moment um so can you can i and someone please give me some uh acknowledgement so can you see the presentation everything okay because right now on youtube it kind of seems that i'm uh that you see my webcam and i'm not sure if the presentation is showing so can you kind of acknowledge that because streaming is really hard and i you know it's really hard to make everything work correctly oh okay thank you thank you luca okay so with that being said uh you know showing and hiding ui state is as simple as adding conditions to your code so compose runs in a way that any number of functions you call they're going to be represented on the ui in the order of uh their call so their call order so which means that if you have something like this where you have a composable uh which is just like a simple mycomposable and you have some condition which if it's um if it checks out if the condition is true you show up positive state composable if it's not true you then show a negative state which can be an error state or uh more instruction on to the user what you want them to do so if you have something like this this is pretty simple this is a pretty simple way of showing two different types of ui depending on your condition um and it's really important to hear to see here that um only one of these functions uh these composable functions will be called and because of that only one of the states will be shown only only one of the ui pieces will be shown so as i mentioned if your condition checks out for example if you try to show a list of items and your condition is that the list of item is not empty then you show that list of items otherwise you show an empty screen or an empty error or something like that then if your list is not empty you're going to show the items which is here in the first part but if it doesn't check out if it falls through to the else case you can show an error view and just say hey you know you no longer have a list of items to show you can just show an error view and this is as simple as that and this is basically all that composes uh here to do so what you can do with all this is you can also have different parts where you change between different types of screens or different types of um actions that are visible to the user based on the current state so for example if you have a box which has some modifiers for example to center the content you have your base content which is your list of items but if there's a specific condition in in line then you have to show a dialogue for example if you if the user long pressed an item you want to show a delete dialog then this condition might represent a variable that actually says if the user has long pressed an item and if they have um you can show a dialog to delete that item this is a really good use case and a really uh really simple way to show sorry excuse me a really simple way to show a dialogue uh where you only show it in based on state and this is all we do in android actually we just show some content and then based on some state we show some dialogues or some extra options or something like that um which means that if you have something more complex like as i mentioned showing a screen based on what the current screen is um and this can be like an enum or a seal class then all that there is to navigation so to say navigation and compose is depending on your current screen you would just show or call a different function and this is pretty much everything that you need to do to share or show different screens based on the state in compose so what happens here is that whenever any of these stay sorry whenever the screen changes uh the when clause is called again because you're observing some state and based on the current state you should you create a different function or call a different composable function and show a different screen so it's as simple as that so if you ever wonder you know how do you actually how do you actually work with compose in order to you know show different uh different content based on your state this is how you do it you just slap on anything else clause or a when statement and that's pretty much it um here's a more concrete example though you might be oh yeah sorry i can move the microphone a bit further and i can also do this um i can make it a bit quieter we had some issues previously um where okay so this should be fine right now uh we had some issues previously where uh with my microphone where it was a bit quiet so i just kind of moved it a bit closer and i also made it a bit more uh more loud so hopefully this is better right now um so as i mentioned uh here's a more concrete example of judging on what i previously built which was like a book reading app we might have some reading lists in our in our app where we show different types of reading lists and you can add books to your reading lists and based on this content we will have a box with some modifiers where we fill in in the max size for the for the box for the content and we also align the content to the center which means that if you decide to show some dialogue or some option it will be centered as well after that we also have a reading list here where the written list composable basically renders the list of reading lists as it mentions so it has different options here we might have like an itemclick callback here which is currently empty we might we might also have um oh where is the point yeah so i need this uh we might also have a on long item tab callback which will notify the view model that we want to delete a reading list and based on that we can change the state to something else uh so here for example after all this content after all this base contact we we can have a variable which says are you showing a reading or sorry at least in this case or are you showing a delete uh reading list dialogue in another case so uh based on this button here he's floating action button we might uh you know notify the the view model that we want to add a new reading list and based on that we can change the state and tell the compose ui component we have which is the reading list content wrapper that we now want to show our add reading list dialog and if we want to do that we just call that function within an if case you don't have to worry about so this might be a bit weird at first when you look at it because you only have an if case but you don't have an else case right um it's completely finding compose that you only have an if case because you might only show uh something in or a component in this case if that case checks out if that condition is true so if you are not showing an add list dialog then you don't have to call any at least function and just not calling the function and not having any else clause is uh good enough so in this case you know whenever we notify the viewmodel that we want to add a new reading list we just show a new dialog but how does this does this actually work underneath and can we actually do more of these calls uh where where uh we do one call and that's a one if case and we have a reading list and everything but we if we want to add another call call another dialog for example the delete list dialog which i mentioned before we can just add another if case it doesn't matter that we have one if case here or another here we can just have another if case a more concrete or more clean way of doing this is maybe if you can only have one dialog active at a time is that you have a seal class which is the currently shown dialog or something like that we can have the add reading list dialog and the delete dialog and based on the currently shown dialog state you can show different dialogues so you would have a one clause here um instead of on a series of if cases um but you know what about the state changes behind the scenes so what happens if we change the state and how do we actually change the state to affect the ui um it's pretty simple you know as i mentioned you know state handling in compose as we discussed previously in the presentation uh in the previous uh gdg meetup we had state change tends to change and because of the state changes the ui redraws itself every time but in a smart way you generally discuss something called recomposition so whenever you change some state you recompose the tree and only change the minimal amount of um oh sorry only apply the minimal amount of changes to measure the new state so we had that this example the previous time we we talked about compose where we had like a container which has a header and a list and if we decide to make some changes to the list and not uh no changes the container or the header what happens in compose well the container and the header don't really redraw but the list is recomposed and because of the res list changes we get a new list with fewer items or if we decide to add new items we get more than we previously had so basically it's really smart in a way where when we change the state it only updates the minimal amount of things which means that in terms of dialogues and everything you can change state as much as you want and it should be pretty pretty pretty fast and pretty uh pre-optimized in that way so this leads us into what i kind of initially wanted to talk about which is how do you connect this in a reactive way that when you change something everything automatically updates you don't have to tell compose to update something uh manually which is what you don't really want to do you want everything to be the clarity you want everything to be reactive so how do you do it um you do it through exposing different pieces of data which are reactive um usually you want uh something like a live data or a flow for your reactive data flows uh you can could essentially use uh something like rx but it's much easier to expose live data because live data has um direct support for jetpack compose you can transform live data sorry uh you can transform uh flows and react reactive extension uh observables into live data through different types of extensions and you can also transform live data into state for uh compose so everything works out of the box you don't really have to worry about using just one thing or just uh or switching to something else if you want to switch to something else as a company other than that you also want to have view models which expose these uh live live data objects or flows or whatever you're using and then compose should connect to those view models and observe their data from within this means that you can rotate your screens and do any number of configuration changes without actually damaging the performance of the app because the view model will um your model will persist that uh that states true live data and through it being a view model and you'll also get uh immediate updates to compose ui because you're now emitting new state uh whenever the the screen recreates itself um so this is a really simple example um that i kind of go through uh several several steps with you um so right now i didn't really show uh previously what the reading list content wrapper uses for state we just kind of show what the composables are so here we have the reading list content wrapper again and this is the state we declare at the very top so we say we have uh four different pieces of states um actually three to be more honest so we have the reading list state which is the current uh set of uh our leading reading list items we also have the delete list state which represents a single uh reading list object that we want to either uh delete or you know show up basically show a dialogue for that we can then later delete or just cancel the dialog and uh leave it be um we also you know take the the current value of the delete state by just you know referencing it um this is a bit important because by default uh the list delete state uh returns a nullable value um and you could return an empty object here as you can see here you can we return an empty list in case there's no value in the live data but this is for me a bit more clean where you declare the current reading list you want to show the um the dialogue for and then you can you know do something based on that we also expose a boolean value here uh through a live data that holds a boolean which represents if the the screen is supposed to show uh an add list or an ad reading list uh dialogue or not um so here i kind of condense it into three lines of code but basically here you can see what the important part is um and how easy it is to connect to uh connect compose to live data so here we access the reading list view model which we have we access the reading list state which is this is a live data so basically from here on uh you come into the reactive world so to say but what we're trying to use here is actually the observe a state function where you take a live data object and convert it into a um state object from just compose this means that whatever you do with this state whatever you know ui you show with these states it's going to be reactive because as soon as this state changes um compose automatically uh it notifies its ui tree and all the ui components that use this state that there's been a change which means that automatically they get updated so uh you don't have to do any like manual uh changing of ui state or anything like that you just change the live data as you would and everything gets recomposed and the ui gets updated out of the box so this is pretty much it like there's nothing really um to go about it it's very simple very easy to just connect to a live data and show the data you want uh show the state you want on the screen and then once you change the data it will update automatically uh so if we kind of try to visualize this as a you know diagram or just as a life cycle of things uh you have your view which is your basically your compose functions which observe the live data from a view model as state and then anytime the live data receives any updates from let's say the repository or from just from the general business logic in your view model or even the api the database anything it automatically receives updates um as long as you let's say use flows or you update the live data and because it receives new updates it also notifies the ui of the new changes which means that essentially uh whenever there's new state from the live data that you listen to the view realizes that it's new state and it recomposes itself so you after this you get a new view that's now updated that again listens to the same live data that again can receive new updates from the repository or wherever you get your data from and it will in turn push new state to the view again going into the recomposition state and back into the new updated state of the view so this is really simple actually if you ever thought that you know handling data would be really complex it's not that complex at all um one of the key things that you can do here is your repository can be also based on um reactive reactive flows for example or just in general you know react to that data structure such as a flow or rx observables or live data if you just use live data where you can return a flow from a database and then everything every time you do something to the database you automatically update both the live data and the ui so you don't generally have to do anything to to show new data on the screen and it's really really really performant and optimized so if we were in within our view model the data would look something like this so here i have um the first piece of data is a bit different from the other so i'll go through that first um so the first piece of light data is the reading list say this is the only piece of information that uh comes from a database and is being persisted so what we do here is we get a flow from the repository uh which communicates to room saying hey give me a flow of reading lists and then we say hey observe this as a live data within the view model scope which means it you will get updates um on the main thread so you can render it uh on the ui uh thread or you can render the actual state uh whenever something changes in the database um this means that whenever you call let's say repository add a new reading list or remove a reading list it will in turn notify the database which will will in turn notify the flow which we have here uh compress it into a like a live data construct and then push it to the ui screen which is really good good and cool because you don't have to do a lot of work yourself um the other type of state that you can kind of store and uh just depends on your use case is anything that you have which is not something that you persist generally so let's say something uh like the boolean flag if you are showing a reading list dialogue or not or the current uh state or the current object of the reading list that you're trying to delete so these types of values you have to persist yourself so to say and you have to handle yourself um and the kind of the the proposed approach or let's say a clean approach to do so is to have a mutable live data that you that is private for your view model and then expose it as a live data that the user or the ui screen can't mutate from outside of the view model or in the ui ui layer if you want this means that you can observe one live data and whenever something changes in the original live data it automatically gets pushed to the ui which means that if you call any functions such as you know add a reading list or something it will update these two properties or any of them and then update your ui accordingly so here we have a function which is uh called on reading list tab and it's really simple real really clean um you don't have to pass any state you don't have to you know pass any callback or anything to notify the ui you just tell the viewmodel hey i tapped on the reading list button and then from there you update the reading list of live data from within the viewmodel to true so that it's showing a dialog now which will in turn update the ui and render something new the same goes for the uh when you you know long tap on a reading list to delete it you just update the state of the current live data the current value of the state and then it will push itself towards the ui screen which will update then uh the list by not having enough uh sorry not having the same number of uh reading lists uh after you delete them uh and as i mentioned uh when you have like a single source of truth such as a database when you add a new reading list you can just say hey i want to update my repository or update my database in this case my room database with a new reading list and then i will reset the state the same goes for deleting a reading list you would just delete it from the database and everything else would will update uh on its own um and here i just created like a small function called on dialog dismiss which resets both of these values because at any point in my app i can have only one dialogue shown so whenever i um close one dialog i know that both should be close i just do the preemptive sort of sort of operation of resetting both of the states here i'm setting the is showing address state to false and delete reading list state to null and that's pretty much it when it comes to like data in terms of um so i'm not sure what happened here yeah so as i mentioned you know uh what what's happening here like again to repeat it really quickly is that you're listening to the repository listening to two rooms entries to the actual database table and by updating room you cause new state to be pushed to that live data which uh in turn updates the ui and the whole process just renders the new state so if you add a new reading list you'll get a list with one more reading list if you delete any of the reading list then you'll get one fewer waiting list so the the question comes where and you know how to hold the state for your composables um it doesn't really matter you know where you uh or how you hold the state or where you kind of call the state as long as you can subscribe to it so this means that it doesn't matter if you're using nvvm or view models from from the jetpack set of tools or architecture components you can use up you know presenter that you wrote yourself or you can use something else and you also don't have to use live data you can use like a different structure um such as uh you know a flow or something else as long as you can convert it to um to states from compose uh i mentioned using live data and view model as the like the easiest way to do things because everything is there are a lot of extensions that are completely built into the dependencies and you don't have to worry about anything so you might have to change up from uh using like rx or uh flows from cotton core things towards the state if you you might have to write um you know functions that do this for you but you don't have to do it for live data you can just use the extension function which is observe state which just you know lets you completely transform everything out of the box um alternatively as i mentioned um you know if you don't want to hold the state uh yeah stay flow sliding in casually you can use that as well although i haven't personally uh additionally you can just hold the data in the view model or a live data and then update everything manually but the better option here would be to hold it in a database and use it as your only source of truth um this means that your uh your app in itself is offline first by default because everything you do with your api for example you automatically um receive uh through your api calls you store it in your database and through that way you push the content to the ui but this means that if you're offline you can show your uh data to your users without actually showing any of those uh you know dirty and um kind of not happy dialogues or states saying you don't have an internet connection we can't really do anything with the app if you refer or defer to a database as being your single source of truth this means that everything is offline first by default and everything is reactive by default because you can um combine your database if it's room withdrew with flow or live data or rx whichever you prefer so that's it in terms of like how do you handle state and another really important part of handling state is handling animations of course because transitions and in animations in general are just another function of state except that the state changes uh quite fast and based on your actions um so as i mentioned in the previous presentation is that animating compose is actually pretty simple it's much easier than you think you don't have to write really complex animations and understand a lot of the animation framework to just do a simple animation um because animations or in this case transitions in compose which are more complex animations are just um a way to change state and then access different parts of that state through property keys so there's something called a property in compose which is also like called a prop key for short and it basically references one value change in the transition you can have an any number of property uh keys in any number of transitions and uh you can update your components accordingly by just observing the state of the transition uh so let's see how to do that so here um i declared a few properties or few prop keys which define different properties we want to animate in our app i have the top margin the title margin and the content margin of my screen here which are all dp prop keys um db prop keys are just keys that represent um state animations around dp's or dense independent pixels so pixels that or basically the size that you use in android to pretty much render anything other than text size of course um you can also pass in a label if you want to observe these animations or try out these animations in the preview window of android studio but these are not not required it's a good thing to have them if you decide to not run your app to run the transition of course um i also created a floating button size here uh which is also a dp pro prop key which is going to represent the size of the um of the floating action button and i also uh had a content alpha which is a float prop key so you can have int float i'm pretty sure you can have double you can also have dp prop keys uh and uh generally you use these different types of keys for different types of properties so obviously the sizes the margins and everything you want to use dp prop keys um for values which are you know like alpha or maybe um you know some fractions or something like that you want to use floats or some other types of numbers if you have them um so these are the this is the first step to declaring or creating your uh transition you create your prop keys that will represent the state that you want to change and that you listen for changes after that you have to define a transition obviously because you're trying to you know transition between one uh one part one states or one one type of state to another um this is a generic function because the transitions you create can have any number of uh states or state types basically every transition is defined within any number of uh values your type can have so in this case you we have a transition of a boolean which means we we can only uh transition from a false statement or a false value to a true value and vice versa uh if you had your let's say an enum key which represents um a transition between different types of button states for example like a press button state select a button state or a checked state if you have like a check as well or maybe even just like a focus state if you have accessibility support then all of these states in an enum could be one of the states from for the transitions but basically you just have to think about what types of values you want to represent for the state and what those values will represent in your ui um so here for example um i'm trying to animate like a nice transition into a screen where i just slowly slide every all the content in and i also change the alpha of the content so it seems like the content is coming in from from like the bottom of the screen and slowly fading in uh which means that in my full state which is the state if the animation is complete or not or if the content is shown or not so this is what my my false value represents i have these values so i say you know within this state um you access the this property this is basically referring the state of the transition uh my new all of this code is within the transition block so i kind of uh didn't mention it here because uh because of you know sake of clarity so to say so i can fit it on on one slide but basically you say for this state i want to have my image margin top at 125 db the image margin top is the dp prop key here which means that it automatically binds this value to to this key so it's similar like having a map um you know a general header map for example where you have a key that's authorization and the value is the actual authorization key here you say i have my dp prop key or my float prop key whatever you want um as let's say the image margin top or content alpha and these are the values this is the actual value for that key for this state um similarly we have the true state which represents if the animation has finished or if the content is shown so if the if the content is shown is true then these are the values uh obviously you can see that from 125 dp of margin tops for the image we'll go to 16 for the size of the button we'll go from zero which is basically not showing the button to 56 and some other values for the margins and finally the alpha will go for from 0.3 to one point f which is basically full alpha right and these are the two states we have for our boolean transition uh again as i mentioned if you had an enum or a sil class you have a state of let's say the press states of a button a state of selected state of focus and so on and so forth so you're limited to the number of types of transition you can have by the number of uh state values you can have so here we have two states and we can only have uh two transitions from false to true and true to false if we were to have three states we could go from uh let's say the first state to the second and third from the second state to the first and third and from the third state um to the first and second if that suits our use case uh so basically you can you know mix and match these states any way you want as long as you know what you're you know kind of trying to represent uh so as i mentioned this is kind of the starting state so here we represent what the value should be at the start um and we'll kind of or sorry we represent what the values values should be for uh the value false can you cycle the states in order to create let's say a jittering animation yes so uh you don't even have to cycle the state there is a special animation type that i'll just go uh that i'll mention uh in a moment which is called um basically repeat use you tell the animation to repeat itself constantly so you say i want to go from one state to another and then completely repeat this animation uh which does and there's an example of on our website we where a person created a hard beating animation but by just changing the size of the of the icon of the heart icon and they used a repeat animation which basically did all the work for them so they didn't have to cycle anything um and as i mentioned you know all of these values represent uh different property values for different property keys within the given state uh and then you define your actual transition so as i mentioned here you have to say from which state you want to go to which state and how the animation or the values are going to be animated so here we say at the bottom we want to have a transition from the false to true state um we're going to use uh we're going to animate the image margin top value using the tween animation uh twin animation is like a very simple animation where it just goes from one uh one um value to the other uh and in not really a linear way but basically it uses some interpolation so it doesn't look uh dull and you give it a duration and that's pretty much it so you can define every single animation uh how it runs if it doesn't um if you don't define it it's going to use like a default interpolation which is uh pretty fast but you should kind of at least mention the duration you want so it doesn't uh go too fast obviously so in your case as you mentioned uh if you want to cycle the states in order to create a jittering animation or a repeat animation something like that instead of using tween uh here you would use um i'm not 100 sure if it's called repeat just but basically it's uh it was you would say image margin top using you know repeat and within you will have to define some some values so how exactly it would repeat itself and that's pretty much it so uh it's really simple you don't have to you know write complex handlers or threads that you have to handle yourself you can just use a simple function so now that we have defined our state here we we defined the transition from the false value to true which represents if the animation has uh completed which is false at the start and true at the end we don't have to define like a reverse animation which would be from the completed state to like a big initial state if you don't need it this is just based on what you need for your application uh and as i mentioned uh the the directions of the animation so to say you define it within this block so you just say which what your starting state is and what your ending state is and uh this basically describes um how the values will change using each of these lines as i mentioned you define which value you want to change and how you want to animate it uh it's a pretty simple dsl using infix functions which you don't really you can use like basic functions but you you're using infix functions to make it a bit nicer where you say i want to animate the image margin top using a tween animation of a thousand milliseconds which is really really cool um so here after we define i'm sorry i've after we defined all this and defined all the you know states we have all the values we have all the transitions we have we we need to create an actual transition so here we stay within the book review details content we want to have a new you know piece of state which represents the animation states for example using the transition function uh this is something that i kind of didn't mention before let me just real quick we're using the transition definition here function within it we're using the transition function and then later we're using a different transition function which is the transition definition which then uses the transition function in remember to create the actual animation so this is a bit you know kind of complicated when you first see it but it's actually really simple uh once you do it at least once um here we say you know what where what what state we want to go so what the two state is and what the initial state is um basically i did it here so that if we decide to uh for some reason this disable animations we can just say that the initial value is going to be true and in that way it's not going to animate at all um other way if we decide to have the initial state as true and the two state to be false we're just going to reverse the animation so basically uh you can just mix and match to any type of state changes you want then we sorry then we take this state and then we pass it down to our ui components that we want to observe the state from so this is the add reading entry button which is the floating action button and the actual book review details information which shows the content um from within the actual ui elements we read the states using the same prop key so we just say hey you know i want this spacer to have a height of whatever this value is uh at any given moment so this is going to read the value uh from the actual animation directly and it does so by accessing it just as if it were a key value map which it is so it you access the state animation through the title margin prop uh sorry title margin top prop key and that's it so the same you can use for the alpha value here to read the the content alpha of the state uh oh sorry and basically any number of other ui elements and i can kind of jump here to uh to my project hopefully you can see this as well so um this is the book review details activity um and i'm just going to quickly scroll through it but basically um where is it is it here yeah this this is it uh transition state so here i i can show you that i'm using the transition state to animate the floating action button but i'm also using it to animate things like the margins margins of everything uh that i list out there so the content margin the title margin and the image margin and i'm also using it to read the content alpha as well so you can just use it on any number of values you want as long as it makes sense for your project obviously and the result is pretty spectacular given that i'm completely oblivious to any kind of good ui um good ui uh practices or just building you know something that looks nice but with all of these changes with just a few uh set of state properties that you change you get the following uh the following example so when i open the screen uh you can see that the entirety of the content just fades in slowly and all of the values just go slow slowly up and you can also see the button uh kind of increasing size or actually coming into the screen so just once again you can see here uh and because there are different values for margins uh for example the entire animation is done in one second and there are different uh values being changed this means that the this image is going to come in a lot faster than let's say uh the content which has a slightly slower change of values and this creates the effect that you know the image comes in quickly and the rest of the content is kind of sluggishly moving in from uh the previous screen um and also at the same time you have your floating button kind of coming in which is like doing like parallel animation so to say so you have this to me i'm really proud of this animation but to me it looks like a really nice animation where you show your content and present your content to the user using only very very few lines of code using just a small animation small transition that you can kind of cook up yourself so this is kind of what the transitions look like and how you can build your transitions and this is really simple because as i mentioned i managed to do it so obviously you can do you you can do it too um i'm just going to kind of jump to the transition here to show the entirety of the code for this transition transition so it's just a matter of defining the the values you need the state you need to you want to animate here how the animation is going to run and then applying that to different types of uh different types of ui elements as i mentioned here you have instead of tween i think you can use something like repeat yeah you can say um yeah animation.repealable so basically say how many iterations you want uh what the animation is going to be so within the actual um like the the animation block you want and what the repeat mode is going to be so i'm just going to drop this real quick and open the um the definition so you can see so you can repeat it to restart the animation you can also repeat it to be like uh in reverse i think you can also re yeah so yeah you can repeat it to restart the animation every single time you can repeat it uh in a way that it reverses so if i were to repeat this in a restart it would uh you know the content would show up from the bottom then it will go back and show up from the bottom again and so on and so forth if i were to reverse it it will go up then go down then go up and go down and so on and so forth so this is really cool because you can repeat in two different ways which are really really nice depending on your use case this is the actual animation that you want to repeat so you have to define this um and there's a good example that i'll kind of link somewhere uh from rayman.com where the person created as i mentioned a heartbeat animation based on like a repeatable animation and any number of iterations um if you want i think i think you can pass in like minus one or something here to just run it indefinitely or something like that or you can just put it like a you know to be a thousand or ten thousand or something like that to like a really large number um and that's pretty much how like the repeat animation looks like um so that's it when it when it comes to like uh transitions um we discussed like some very simple uh animate blocks and value-based animations previously but this is like a more complex example and it's really cool that you can see that it's not actually complex at all it's very very simple to to concoct something like this and have a nice uh animation your in your app even if you are not ui savvy just like me sorry so the next thing like the final thing that we'll uh discuss today that i'll kind of show you how to do um is maximizing your usability with generics how you can use generic functions to make something completely reusable across different parts of your app and maybe even push it to like a different project so one of the things that you know you can reuse in your project is a rating bar but you generally reuse your rating bars in the same way you always show a rating bar you always show some rating you generally have just like uh five stars or something and that's pretty much it so that's not really generic you know that's a component that's very usable but it's the same behavior but sometimes you can generify like complete components things like you know using dialogues using user prompts or input prompts or menus even all these things are generally always the same the only thing that's changed is the data set um so for example something a good really good example here that i have is a delete dialog you could just create a small generic function which it takes an item of any type it's uh and it receives a callback that pushes that item of any type back to the user when you decide to delete it for example this is a very simple composable in its essence where you take that item you take a message that you want to show to the user um you want you take the callback that you have to notify yourself with uh to delete the item and then if you want to dismiss the uh the dialogue you can also notify yourself about that um the actual implementation and i'm sorry the the slides editing the or highlighting doesn't work here because it's kind of a weird example um but basically you use an alert dialog which is the compose component which has the dismiss request that you passed in you you show the title which is the delete title in this case every single time the message uh and then you show uh two buttons one of which will be the delete button which will represent yes delete this item as an action and the other will be cancel the cancel button which will represent no don't delete this item so within the actual click action you just say delete this item and you already passed past it in so you can just send it back uh and this is completely generic because you can just say uh you know you can go to your um you know your book screen in in my example you can say i want to delete a book and this is the code you would use you just pass in a book you will pass in the message what happens when you want to delete a book so you uh remove the book and you can also cancel the dialogue if you uh don't remove it here or something like that and uh once you dismiss um the dialogue what happens as well and then uh you can go to a different screen and if you want to delete let's say a reading list all that would be different here is that you would pass in a reading list here instead of a book um and you would pass the name of the reading list here as well and instead of you know calling book reviews uh sorry book view model remove the book you will call reading list view model remove this reading list and that's pretty much it so this is completely generic and you can reuse it across the app and you can also ship a set of these components into like a foundation or like a base module or something like that and ship it as a as a library that other people can use so this is really reusable uh very simple example uh in the same manner is a spinner picker so you know having a spinner menu or something like that that you can pick different items from uh again it's generic again you pass in some text to show to the user which is the like the current picked item um or like an extra explanation if you want you pass in which item you want to have pre-selected you can pass in null because um sometimes you don't have a pre-selected item you pass in a list of items how to name each item so this is like a mapper function from the item to the item name that you're going that you're going to show in the picker and finally you pass in a callback that notifies you when an item has been picked within the picker this is a bit different from from before you have some state that you represent that you um persist which is if if the picker is expanded or not and what the current picked item is uh and this is a string so this is either uh like the pre-selected item that you try to you know parse into a string or you show none if you want to show something like uh none to the user or something else uh and then you have a drop down menu from compose where you say hey this is going to be my toggle button it's going to show the picker text and on when you when i click it it's going to change the value of if if the picker is expanded or not to true and this in turn will expand the picker or close it under dismiss request is going to just um change the picker speaker expanded value to false which will stop showing the dialog or the picker and finally you have some like modifiers but what's important is within the picker you just say you know for my picker for for my picker content which is this little lambda block you say for each item i want to create a new drop down menu item which will trigger my generic callback so this is like a generic for loop it will change the picker value to false so it will stop showing the picker it will also change the currently picked item using that transform function that mapper from the item to a string and it will show that uh within the drop down menu it will show a small text with which holds that item so you would have like a small um picker basically that shows you a list of your let's say books or your reading lists or your genres in your in your app or anything basically that you feel like you could use a picker or a spinner picker for and this is one of the the example usages you can just say hey i want a spinner picker to show my jars i want to have the currently selected one to be pre-selected i want whenever i pick azure i want the filter to update um and i want the picker text to be you know this this little string which represents this that you're selecting a picker and whenever i want to show a picker item i'm going to use this transformer transformation function which takes the genre and takes its name as as the actual picker text and that's pretty much it you don't have to worry about um you know having different types of logic for different types of picker pickers every single picker is pretty much the same every single dialogue is pretty much the same so you can completely reuse it and ship this to any number of projects and then just have generic behavior that you don't really have to worry about and this is basically how the lists uh like how lists and compose work how other components work in other you know ui frameworks you just have a generic thing that represents um your items and then you just say what types of items you want to show and how do you want those items to be rendered and that's pretty much it and that's actually it for today um everything you need to kind of follow up with this content you can find in my github repo which i updated with new new examples with new new content as i mentioned you can also follow my jetpack compose course that i really dive into uh compose with a lot of episodes a lot of content it's a couple of hours long so you can go through a lot of content um there's also a couple of tutorials on the right window on website where you can just look up um jeff composed content uh such as you know that animation tutorial as i mentioned um which i'll just kind of uh let me just see yeah i have the link here ready so i can just show uh send it to you so this should be the link um for the animations tutorial for jfk compose and here you can see there are different types of animations and also different types of like types of animations in terms of repeatable animations and tween animations so and so forth so you can uh hop onto that and stay tuned for more composed content we're going to have some pretty big updates in the in about a few weeks so stay tuned for more and we'll and we'll definitely uh jump uh to do some question q a um if you have any kinds of questions and thank you for for being here and for listening to the presentation so are there any any questions that i can um help you with or anything that that's not really said in the presentation yeah the gnome distribution is just amazing uh oh yeah also the presentation i'll share it right after the the what you want to call the the event but you can also you can also see it here if you just want to jump on it real quick let me just move my screen here uh so are there any any questions in terms of compose some advanced stuff for compose how how can you you know do something or uh you know even if i kind of didn't explain anything or something well enough in my presentation uh do you want me to explain a bit more you don't have very many people here today i guess it's like a you know weird time slot or something or more people are going to come later but you know if you have any questions just feel free to ask them okay cool well this kind of makes my job a bit easier if there are no questions um so if there are no questions really uh we can just you know if you come up with anything later you can just ping me directly as i mentioned through the links that i provide in the presentation um you can ping the jdg austriac uh you know email or even our website or even our you know chat here com in the comments below you can just feel free to ask any questions thank you paolo um for for the kind words uh just feel you know if you come up with anything feel free to reach out to us and we'll answer those questions later uh once you come up with them um yeah uh thank you for that i'm really proud of the animations because i suck with ui generally um and this seemed like a small and nice thing that i managed to build uh just you know from the top of my head so uh this just goes to show you know how simple animations are in compose how easy you can create something on your own how easy you can tweak to your use cases um previously i showed that you can like change the size and corner radius and different modifiers for different um ui elements based on your animation state and if you combine that with the animation the transition that i just did then you can create something really really spectacular where you can have the image come from the bottom with a margin and then you can change its size um to just fill up the screen and also change its corner radius so it seems like the image is slowly coming into the screen and filling up the the space the area that they can take so you can create something really really cool like that with very very little effort to be honest as long as you you know know what you're kind of going for with your animations which is i guess something that all animations have in common you just have to know what what you're trying to to what information you're trying to convey with them okay so as i mentioned you know if there are no no questions uh i would like to thank you once more for joining us uh if you have any ideas for any presentations in the future again let us know we'll organize something definitely we're always willing to um we're always willing to show new content or research something new and then try to build something cool with it and you know teach that to to other folks as well if you have um if you want to present something at gdg just again feel free to reach out we'll we're more more the sorry we are more more than welcome to um get more speakers up and have a more diverse set of you know speakers and topics as well it doesn't have to be just android or just compose it can be anything so just let us know and i guess we'll see each other in the next presentation uh thank you again for joining uh make sure to you know share this video with your friends if you think they'll get something out of it make sure to comment below if you found it really cool and if you have any other questions and we'll see each other the next time bye guys bye everyone
Info
Channel: GDG Osijek
Views: 2,304
Rating: 4.9101124 out of 5
Keywords:
Id: eL3G1Basx1o
Channel Id: undefined
Length: 66min 25sec (3985 seconds)
Published: Wed Jan 20 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.