Flutter Elastic Navigation Sidebar | Flutter UI Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hey hello fans and welcome to retro portal studio and in this video we're gonna be taking a look at creating this nice elastic sidebar in flutter which when pulled out creates this nice elastic effect let me show you again so along with this elastic fact as we move the cursor inside the sidebar you can see that the right-hand side of the sidebar flexes itself depending upon the position of the cursor and as the cursor moves on any of the item in the sidebar the size of that item changes and also when we close the sidebar it closes with an elastic effect and when we open the sidebar you can see that the arrow shifts in the end let me just open this again and you can see the nice simple animation there so in this tutorial we're gonna be talking about some of the relatively advanced concepts of clutter UI and so you can implement those concepts in your own ways in your flutter applications so let's get started okay so right now I'm gonna simple flutter app in which I just have this my home page which is a stateful widget and in this state for widget I have a scaffold which is covered by a safe area and it further contains a container and with the help of this container we're getting this nice gradient here along with this I have given a width to the container with the help of this media query that I have declared here in the build function so along with this I also have a stack as a child of this container and in the stack I have placed a simple material button that says hello world along with this I also have this assets folder in the application in which I just have a simple image which we're going to use as an image in the sidebar that we're going to create so the way we're gonna create this sidebar is by adding another child to this stack in the container so for that I just come down the center and create a new child that is going to be of sized box and the sized box will contain the sidebar so for this I'm gonna use a width property and for this width I'll come up here in the build function and create a new double and named this sidebar size and put this equal to media query dot width and multiply that by 0.65 so basically the sidebar is going to take 65% of the width of the screen so I'm going to use the same size as the size of the sized box and next I'm going to add a child to this signed box and this child of the sized box is going to be a stack and the reason for adding a stack here is going to be clear to you in just a few moments so in this stack I'll add a children property and the first child of the stack is going to be a custom paint for this custom paint I'll pass in the size property and the size is going to be an instance of size class' and for this I'm going to pass the width of sidebar size and height of media curry dot height I'm just going to minimize the emulator so other than the science we also need to pass this a painter and for this we need to create a custom painter of our own so if you don't know much about the custom painter and how to use it you can check out my tutorial on creating a custom paint application in flutter and from that you can get the concept of this custom painter and how to use that into your own flutter applications so for this painter I'm just going to create a new class down here and I'll just name this draw painter and this will extend custom painter so this custom painter requires me to implement two methods so here in the should repaint function I'll just pass through and paint is the function in which the magic is going to happen so first in the paint I'll just create a new paint object and put it equal to a new paint and by using the double dot operator I'll just put the color and put it equal to colors dot white and also give it a style and give it a paint style or fill the next thing that I need to do is I need to create a new path so I'll just name this path and put it equal to a new instance of path so to understand the path that we're going to create I'm just going to give you a simple demonstration here in this demonstration this black box is the screen of our app and this dashed box is basically the drawer so at this point in our application what we simply need to do is we need to create this dotted box and in this donut box you can see that we have four points here that is minus with comma zero with comma zero with coma height and minus width coma height and width here is basically going to be equal to 65% of the screen that we have declared in the build function of a wrap so basically we need to create a simple path and the path is going to start from - with Tacoma zero it's going to create a line - with Tacoma zero and then we're gonna create a line from wit comma zero to wit coma height and then we're gonna extend that line to - with Tacoma height and then we're gonna close that path so let's do that in code so in the paint function we can get the width from this science property and for creating a path the first thing that I need to do is I need to create a point and for that I'll use path dot move - and in here I need to pass - size dot width comma zero so after this we need to create a line and for that I can do path dot line - and pass in the second point and like I presented to you in the diagram the second point is going to be size dot width comma 0 from here I need to create two more lines which are going to be simply like this and at last we need to close the path that can be done using path dot flows so next what we need to do is we need to paint this path on the canvas and for that we can use this canvas that is given to the paint function and here I can use canvas dot draw path and in this I simply need to pass the path and the paint and at this point I need to pass the instance of this draw painter to custom paint so at this point if I run the app you can see that we have a nice custom painted rectangle where a sidebar should be and this rectangle basically extends beyond the screen which is currently not visible to us and the reason for extending this box is going to be clear to you by the end of this tutorial the next thing that we need to do is we need to make this custom painter react to the position of the cursor on the screen and for that we can wrap the stack with a gesture detector so in this gesture detector we need to use a function called own pan update and this own pan updates requires a function to which it gives details of the click and the other property that we need to use is own pan and and this also requires same kind of a function to which it gives the details by using the own pan update we can get the users click on the screen and then we can get the updates as the user moves the finger on the screen and with the help of own band ends we can detect when the user clicks off of the screen so what we need to do here is we need to get the position and put that into my homepage State for that I'll just create a new variable in my homepage state of type offset and I'll name it underscore offset to give it private and give it an initial value of offset of zero comma zero then an on pan update I need to set the state and here I need to set the value of offset equal to details that local position and this local position will give us an offset that will be equal to the location of the users finger on the screen and this on pan update will also update us as soon as the user moves the finger on the screen and we'll set that value to the state also and as soon as the user picks up the finger from the screen we need to reset the value of offset to zero comma zero so for that in on pan and I'll to set state and here I'll set the value of offset to new instance of offset that is going to be zero comma zero and by doing this we're keeping the track of users fingers position on the screen so to update the custom painter according to this offset we need to pass this offset to the draw painter and for that I'll come down to this draw painter and in here I'll create a new constructor and passing the named parameters of this offset and we also need to create a final variable of type offset and I'll name this offset once this is done we can go up to the custom paint and in here I can pass in the offset property and put it equal to underscore offset and I'll just minimize the emulator now we need to use this offset to update the path of the custom painter and to make you understand how to do that we need to go to the diagram again with the help of this diagram you can see that up till now in our application we have created a straight line from width comma zero to wit comma height but in actual application what we need to do is we need to use a Bezier curve to create a curved line from width comma zero to with coma height and we need to change this curve according to the fingers position on the screen so to create a Bezier curve we need to get a control point and an end point which is going to be with coma height so to get the control points for this Bezier curve we're going to get the position of users finger on the screen and then we're going to map that position to get a new control point for this bizarre curve to understand what a bizarre curve is and how to use it I suggest you to check this article on medium in here you can see that p1 is the control point and P naught is the starting point and p2 is the end point in our diagram the end point is going to be the bottom of the screen and the control point is going to be this one so by giving a read to this article you can understand quadratic Bezier curve in a much better way coming back to the code we need to remove this line here and in place of this we need to use a quadratic Bezier curve and for this x1 and y1 is going to be the control point and for that I'll just pass offset dot DX that is going to be the x position and for the Y I'm going to pass offset dy we're going to change this x-value soon but for now this is fine for the value of this x2 I'm gonna pass sighs Dartmouth and for value of this Y 2 I'm gonna pass size dot height and at this point if I run the app and go to the emulator you can see that we have this weird curve on the app other than this curve here there's also another problem if the cursor moves inside the sidebar the sidebar flexes on the inside and we don't want this to happen we want the sidebar to flex only on the outer side so for that we have to change the value of the X control point of Bezier curve for that I need to create a simple function here so the return type of a function is going to be a double and I'll just name this get control point X and this function also requires a double that it will be the value of width and in this function I need to create a simple check if the offset DX is equal to zero then we're gonna simply return the value of width and this will fix the problem of curve that we have here we also need to add an else clause and in this we need to return a conditional output here we need to check if the offset DX is greater than width only then will return the value of offset DX or else will return a value of width plus 75 and I'll use this function as the first argument of this quadratic Bezier curve and in here on each passing the value of sighs width so at this point if I run the app and go to the emulator you can see that even if I move the point inside of the side bar the side bar doesn't flex on the inside it always flexes on the outside and also the problem of the initial curve is gone so we have solved the two problems that we had but at this point there is another problem in case I have my cursor inside the side bar and I move the cursor outside you can see that there is a small moments of flicker and this is because in case of this get control point X worth checking if the value of offset D X is greater than width then we're passing the value of offset DX or else we're passing the value of width plus 75 so initially when the pointer is inside the side bar this value is given but as soon as the pointer moves outside the bounds the value changes to offset DX and this creates the flicker so the solution for this problem is also a required feature of our application because we don't want the user to control the Flex from outside the bounds of the side bar so to solve this problem what we have to do is we have to go up here in the gesture detector and in the on pan update we need to check if the details that local position that DX is less than or equal to sidebar size I'll just minimize the emulator and if this is true only then we're going to set the state to the new offset value so basically we're checking if the position of the users finger on the screen is less than the sidebar size only then we're gonna set the value of offset or else we're gonna do nothing so at this point if I run the app and go to the emulator you can see that if I move the finger inside the sidebar the sidebar flexes but as soon as my finger moves outside the sidebar there is completely no change and if I lift up the finger the sidebar moves to its initial position so at this point we have created the behavior that we want from our sidebar in the next step we need to add the content to the sidebar so I'll just minimize the emulator and for adding the content what I'll do is I'll come below the custom painter and here I'll add a container in the container I'll add the height property and put this equal to media query dot height and also add the width and put it equal to sidebar size other than this I'll also add a child of column in the column I'll set the main axis alignment to main axis alignment dot Center and also set the main exercise and put it equal to main exercise max in the children property I'll add a container and in this container I'll set the height to be equal to media query dot height and multiply that by 0.25 so basically the height of this container is going to be 25% of the height of the screen and in this container I'll set the child property equal to center and in this center I'll put the child equal to column in the children property of this column I'll add a few elements such as an image and a text after this container I'll add a new divider and set its thickness to 1 after the divider I'll add another container and for this container I'll set the width to double infinity with this width the container will take the maximum width available and also we need to set the height of the container for the height what I'll do is I'll create another variable and this variable is going to be of type double and I'll name this menu container height and put it equal to media curry dot height by 2 and I'll use this height as the value of height for the container for the child property of the container I'll add a new column and in this column I'll add the children property and here I'll add five buttons and each of the button comes from a stateless widget that we have created here that is called my button and in this I have simple properties like text icon text size and height so because we're having five buttons in the container we're getting the height as 1/5 of the total height of the container and we're gonna pass that height to the my button in the build function I have this material button in which I have a row in which I have the icon sized box and the text I also have the on pressed function in which I haven't limited anything so the reason for adding container as the primary elements of this column is because we want to get the position of each of these buttons and for that we're gonna be using the global key and because it won't be a good approach to create five global keys instead we wrap all these buttons in a column and put that column as a child of the container with the help of this we will be able to get the position of the container and in relation we'll find out the position of all these five buttons to explain this let's look at the diagram so with the help of this diagram you can see that for the total sidebar we have this complete container and this we have column and in the column we have these two containers with the first container having the height of 25% and with a second container of having height of 50% so in the second container there are going to be five buttons and for the each button the height is going to be the height of second container divided by five this approach is useful because for the final version of the app we have to increase the size of these elements as soon as the cursor moves on them so for that we have to get the location of each of these buttons for getting the location we will be using the global key so in case if we have added each and every element as a separate element to the column we'll have to use five global keys but in this case we'll add the global key to this container and then we'll get the position of this container and respective to this container we'll get the position of all these five buttons and then we'll use those positions to increase the size of these buttons as soon as the cursor moves on them so let's get back to the code and implement this so the first thing that I'll do is I'll come up to the my home page State and here I'll create a new global key and put it equal to a new instance of global key and I'll use this key in the container that has all the five buttons I'll add the key property and set it equal to global key once this is done we can use this key to get the position of this container and then relatively get the position of all these buttons but before we get the position of these buttons we need to create a list in which we have to store the positions so for that I'll come back up to the state and here I'll create a list of double and named this limits and put it equal to an empty list so to get the position of all these buns we need to wait until the first frame of the application is rendered and for that we need to use a specific function what I'll do is I'll I'll write the init state function and in here I'll use widgets binding dot instance dot add post frame callback and with the help of this function we'll wait until the first frame of the application is built and after that we'll get the position of the container and then we'll find the location of all the buttons so basically we're waiting until the first frame of the screen is rendered and as soon as the screen is rendered we're gonna call function here so for getting the positions I'll create a new function and name this get positions and because we're gonna use this function in the on post frame callback we're gonna give this an argument of duration I'll just call this function here in the callback and in the get position function what I'll do is I'll use the global key I'll get the current context and use the find render object function and I'll store the results in a render box object once this is done I'll use the render box to get the location of the object which in this case is the container so I'll use the local to global function and in this I'll pass offset dot 0 and I'll throw the results in final position so basically this is the position of container on the screen once the frame is rendered so using this position and the height of the container will detect the starting and ending points of all the five buttons of the container so for that I'll just create a new variable and name this start and put it equal to position dy and I'm gonna subtract a value of 20 and 20 is basically an assumption for the height of the status bar because the position will start from 0 0 that is at the top of the status bar but because we won't be counting any height of the status bar and subtracting the value of 20 from the position that we have received from the render box in the same way I'll create a consider limit and I'll put its value equal to position dy Plus render box dot size dot height minus 20 so in this case I'm getting the position that is for the end of the container for that I'm adding the start position with the height of the container and subtracting a value of 20 for the same reasons we did with the start once this is done I need to calculate the height of each button so for that I'll create a new variable and name this equal to step and this will be equal to the container limit - start divided by five because there are five buttons after this I'll create a for loop that looks something like this and this I'm starting from the value of start and going to the value of Container limits and for each iteration I'm increasing the value by step so basically the first value is going to be the starting point of the container the second point is going to be the end point of the first button the third value is going to be the end point of second button the fourth value is going to be the end point of third button and so on and simultaneously were adding those values to the limits list and also before the for loop I need to set this list equal to an empty list and after this I'll call this set state function and here I'll set the value of limits equal to limits by doing this will recall the bill function and all the buttons will get refreshed so the next thing that we'll do is so comes down to the buttons so here you can see that for each button we have a constant text size of 20 but what we need to do is we need to check if the cursor moves inside the button and at that point we need to change this text size to something else so for that I'll come up here and create a simple function so this function will basically return a double value and I'll name this get size and in this function we need to pass the index of the button so basically in this i'll get the size and the value of the size will depend upon a condition and the condition will look something like this so basically we're checking if the y position of the cursor is greater than the starting position of the button and is less than the ending of the button then that means that the cursor is on the button and in that case we pass in the size of 25 or else we'll send the size of 20 so I'll come down to the button and in place of 20 I'll use the gate size function and pass in the index of zero because this is the first button and I'll do the same thing for each and every button at this point if I run the app you can see that there is an error of valid value range is empty and this is because when the view is first is we can go to the init state function and initialize the value of limits and put it equal to a list of 6 zeros now have run the app and go to the emulator you can see that all the buttons are now visible but if we move the cursor over the buttons nothing happens the reason for this is because in the get size function we never return the size so this was just a bug and if I restart the app you can see the designs of the buttons changes and by default each of the one is having a size of 20 and as soon as I drop the cursor and move over the button the size of the button changes to 25 and as soon as the cursor leaves the button the size reverts back to 20 and this happens for each and every button and also the right-hand side of the side box is changing its curve values depending upon the position of the cursor so at this point we have almost completed the UI design now all we need to do is is we need to find a way to close the sidebar and that is what we'll do next for detecting the open and close state of the sidebar I'll create a new boolean call is many open and set it equal to false so initially the sidebar will not be open and for animating the sidebar or come down here to the sized box and I'll wrap the science box with animated positions for the animated positions I'll add the duration property and set it equal to 1,500 milliseconds after this I'll set the left property and I'll check if the is menu open is true then I'll set the value to 0 or else I'll set the value to - sidebar size plus 20 I'll set the value of top-20 else valley of curves two curves elastic outs and at this point if I run the app and go to the emulator you can see that only a certain portion of the sidebar is physical and this is because we've added the value of 20 to the - sidebar size but now we don't have any way to open the sidebar in this case what we need to do is we need to detect if the user has clicked on the site and dragged to the right-hand side then we'll need to open the sidebar so for that what we need to do is we need to go back to this own pan update function and here we also need to add another condition here I'll check if the details that local position D X is greater than sidebar size minus 20 because this 20 is the width of the sidebar that is always visible on the screen and if the value of this pointer is in that region and other than this if the distance dragged which can retrieved my details Delta distance squared is greater than 2 then what we'll do is we'll set the state and set the is menu open to true so at this point if I run the app and go to the emulator you can see if I click on it and drag the menu the sidebar comes outside now what we need to do is we need to find a way to close the sidebar so for that I'll add a simple arrow to the bottom right corner of a sidebar to do this I'll come down here in the stack and at the end of the second container we add another button so this is a basic icon button which is wrapped in the animated position and in here if we click on the button then this will set the East menu open to false so at this point if I run the app and go to the emulator you can see that we can click on the side and drag it and the sidebar comes from the left-hand side and if we click on the button the sidebar gets closed I'll just open the sidebar again and you can see that the bottom itself gets animated and I click on the button and open the drawer again the button animates itself to the position so in the end this is the sidebar with nice fluid animations I hope you find this video useful and if you do please hit the like and subscribe button and also consider supporting me on patreon for all the flutter videos coming up on retro portal studio see you next time peace [Music]
Info
Channel: RetroPortal Studio
Views: 24,634
Rating: undefined out of 5
Keywords: flutter, flutter ui, flutter sidebar, flutter sidebar and navigation, sidebar and navigation flutter, flutter animated sidebar, flutter elastic sidebar, flutter fluid sidebar and navigation, flutter animated navigation, flutter custom painter, flutter advanced ui, flutter animation, flutter navigation, flutter fluid ui, flutter design tutorial, flutter tutorial for beginners, sidebar animation flutter, flutter ui tutorial, flutter widgets, flutter tutorial
Id: 1KurAaGLwHc
Channel Id: undefined
Length: 26min 52sec (1612 seconds)
Published: Sun Apr 05 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.