Flutter Avatar Widget (example of ChangeNotifier & ValueNotifier & mathematically formulated badge positioning)
Lets design an avatar widget with badge having these features:
- Avatar widget would be any asking size. And of course the badge also.
- Widget’s shape would be chosen (i will design two shape class: Circle and Square). Square borders’ radius would be changable.
- Avatar badge position would be chosen: combination of [top, center, bottom] x [left, center, right]
- Avatar badge would be positioned on shape line (and yes, no matter shape, border radius, avatar widget size, badge size etc.). But how? Avatar badge position would be calculated with mathematical formulation.
- And the perfect side of this design: Some features would be change notified. An example scenario; when we change the picture, avatar badge would not re-build. (will increase performance)
Lets start with show widget result and please focus on avatar widget.
Lets create a generic class named CustomChangeNotifier which notify listeners when value changed. ChangeNotifier class do the same thing, but we will use a function named as ‘change’, which increase readability and more understandable.
We’ll use this class on defining variables that have to notify listeners after value changing. Please notice that first initialization would not notify listeners.
Now, design our abstract avatar shape class and its change notifier. Notice that, we define shape size variable as CustomChangeNotifier. Thus, we can reach change notifier of avatar size or we can use AvatarShapeChangeNotifier class to be notified on any variable change. I re-calculate border radius on size changing with rate of size change amount, so the exact shape will not broken.
Lets design two avatar shape class. Circle and Square. Circle borders’ radius will automatically calculated. But Square shape borders’ radius amount will be changeable.
Then, lets create class of badge model and its change notifier including necessary variable definitions. See that, define color, size, border size and color as CustomChangeNotifier class. And notice that when we design badge model change notifier, we just add notifyListeners function as a listener to changable variables’ notifier. It will trigger badge model notifier on any value change. This design will be perfect, because we can reach every variables’ change notifier and/or the general badge change notifier.
And now, we can design stateless Avatar Badge widget which takes a Badge model and builds by this model:
Notice that, ValueListenableBuilder listening to badge change notifier, each notification will cause re-build the widget. And yes, this widget is stateless. You can design your change listeners via your needs. Interventions on badge model class would reflect on the widget instantly, if model change notifier is listening related variable changes.
Now, we can create avatar model and its change listener.
I will explain how calculateBadgePaddingAmount function is working and calculates amount of what, why we need it? What is its’ formulation?
Firstly, we design avatar widget itself:
Lets see what we calculated?
See avatar widget, we create a stack widget inside a container which has avatar shape width and height. And we decide position of badge with Alignment value (suppose it is top-right)
if (badgePosition == Alignment.topRight)
_badgePaddingAmount = shape.topRightBorderRadius * 0.29;
else if (badgePosition == Alignment.topLeft)
_badgePaddingAmount = shape.topLeftBorderRadius * 0.29;
else if (badgePosition == Alignment.bottomRight)
_badgePaddingAmount = shape.bottomRightBorderRadius * 0.29;
else if (badgePosition == Alignment.bottomLeft)
_badgePaddingAmount = shape.bottomLeftBorderRadius * 0.29;
_badgePaddingAmount - (badgeModel.size / 2) + (borderSize / 2) - 1;
- If badge positioned on a corner, border radius of this corner * 0,29 will give us avatar badge radius position over avatar widget radius.
- If this amount is less than zero, it means no need to move badge, we have to shrink avatar shape (see calculateBadgeContainerPadding function).
- If this amount is bigger than zero, calculateBadgePadding function will calculate which side we have to slide the badge to place badge on the shape line.
This formula will give us an advantage that we can create more different shaped avatar, like:
I am using EmptyWidget class when i need place nothing (some widgets don’t accept ‘null’ variable/widget). If you wonder that how EmptyWidget is designed:
I am using this widget on my flutter chat app project (still under development), you can see this in action.