How do I paint an InkResponse above other widgets? - flutter

I have a LeafRenderObjectWidget in a Column:
Column(children: [CustomRenderObject(), InkResponse(child: ..), ...])
Below that, there is an InkResponse. Normally, the splash and highlight from the InkResponse would draw above the previous widget in the Column. If I had the following scenario, the highlight and splash would be rendered above the Container:
Column(children: [Container(height: ..), InkResponse(child: ..), ...])
However, in my scenario with the RenderObject, anything I draw at the bottom of my CustomRenderObject widget in the paint method of my RenderBox will be drawn above the InkResponse splash and highlight.
The Material is a parent of the Column.
This means that my InkReponse highlight and splash are cut off at the top. I do not want to add additional padding to my InkResponse. How can I have my InkResponse draw above my RenderBox?

Solutions to this problem are described in the troubleshooting section of the InkResponse class.
If you are just using a simple colored Container or something similar, you can use the Ink widget instead, which will paint onto the Material and thus render the InkResponse's highlight and splash above.
Another solution would be adding a Material of type MaterialType.transparency:
Material(type: MaterialType.transparency, child: InkResponse(..))
This would go right below the InkResponse itself. However, this does not solve my problem as it clips the InkResponse into a rectangle.

The InkResponse will draw the splash above the parent widget in the tree and not in the siblings. That explains why it is painting in your Material widget that is above the Column because the Column itself is just a layout MultiChildRenderObjectWidget.
The solution that you provided, is actually a good approach that is used sometimes, but since you want to render the splash effect in your LeafRenderObjectWidget, and because it has not children, Flutter doesn't know where actually you want to render the splash effect. I'm afraid you can't use InkResponse to render splashes in a leaf widget.
An ugly solution that might work, can go from using a Stack to place each widget on the top of the other but you'd still have to make sure they would have the same appearance. If it is a complex render object, this can be tricky.

Related

How to prevent widgets from being hidden behind the system status bar

So I am creating a new flutter widget and I am unable to understand how my app looks because of the space on top of the screen in my emulator,
As you can see there is a shaded area on top and my widgets are under it, is there any way to remove it?
Use Safe Area.
SafeArea is basically a glorified Padding widget. If you wrap another widget with SafeArea, it adds any necessary padding needed to keep your widget from being blocked by the system status bar, notches, holes, rounded corners, and other "creative" features by manufacturers.
Check this link for more.
Wrap your code with the SafeArea.
more info about SafeArea class

Should I always use a SafeArea at the top level of my flutter screens?

I am curious if I should always use a SafeArea widget at the top level of my screen. I mean....when would I want my content blocked by things like a notch? For me it seems like the answer is never.
So should I not just use SafeArea on every page? If so, should it be above or below the Scaffold widget?
You don't have to use SafeArea on every screen. It actually depends if an AppBar is used or not, because the AppBar automatically calculates the values and adds the required padding.
If you use it above a Scaffold the area where the padding is applied would be black. On the other hand, if you use it below the Scaffold the color of the area would depend on the app theme, probably the Scaffold background color.
If you won't add an app bar or add it. if you want to adjust the screen to be responsive using MediaQuery and you don't need any scroll inside the screen use it.
Use it as the first widget in the body of the scaffold.

What's the difference between raisedButton and Container with onTap() (Flutter)?

When we want to achieve a button, we can choose raisedButton in flutter lib, also can a Container with onTap() function. So what's the difference between the two and which one should we choose in different situation?
Container function doesnot have onTap option, but you can achieve it by wrapping it in Guesture detector or Inkwell. There are no changes in the backend. But Raised button gives you the elevation, and animation on tap. You can also do it in the container, but it requires you to manually do it.
If you want a simple button quickly use RaisedButton.
If you want a more complex one, use Container or mixture of Containers, RaisedButton etc.
I am gonna offer something different... A tale of a treasure that is known to have answers to many questions, use cases and sometimes even examples. The name of this treasure is: official documentation. ;)
RaisedButton
A raised button is based on a Material widget whose Material.elevation increases when the button is pressed. Use raised buttons to add dimension to otherwise mostly flat layouts, e.g. in long busy lists of content, or in wide spaces. Avoid using raised buttons on already-raised content such as dialogs or cards.
Container
A convenience widget that combines common painting, positioning, and
sizing widgets.
GestureDetector
A widget that detects gestures. Attempts to recognize gestures that
correspond to its non-null callbacks. If this widget has a child, it
defers to that child for its sizing behavior. If it does not have a
child, it grows to fit the parent instead. By default a
GestureDetector with an invisible child ignores touches; this behavior
can be controlled with behavior. GestureDetector also listens for
accessibility events and maps them to the callbacks. To ignore
accessibility events, set excludeFromSemantics to true. See
flutter.dev/gestures/ for additional information. Material design
applications typically react to touches with ink splash effects. The
InkWell class implements this effect and can be used in place of a
GestureDetector for handling taps.
InkWell
A rectangular area of a Material that responds to touch. For a variant
of this widget that does not clip splashes, see InkResponse... The
InkWell widget must have a Material widget as an ancestor. The
Material widget is where the ink reactions are actually painted. This
matches the material design premise wherein the Material is what is
actually reacting to touches by spreading ink.
Well, technically you are right, they can both react to a click event. But a RaisedButton will have all the styles specific to the target platform taken care of for you (it inherits from MaterialButton).
note that it's the same in html: you can use a regular div with a click handler or use a button tag. The button will have a few styles already taken care of for you...

Things to be aware of when using a container as a parent instead of MaterialApp/Scaffold

Say I'm building an app that doesn't need Material design elements and use a container as a parent.
Are there things that need to be set up manually (layout-wise) that's unnecessary when using MaterialApp/Scaffold?
Following are few unexpected behaviors I noticed when using a container as a parent:
• Yellow lines in Text widgets (These lines disappear when using Scaffold instead)
• ClipRRect widget takes up the full screen even when I set constraints
Material class is a main component of your UI. Using a Material Widget as parent doesn't mean you are forced to use Material Design for your entire app, you can do your own custom Widgets, UI, etc.
As part of the official documentation:
The Material widget is responsible for:
Clipping: If clipBehavior is not Clip.none, Material clips its widget sub-tree to the shape specified by shape, type, and borderRadius. By default, clipBehavior is Clip.none for performance considerations.
Elevation: Material elevates its widget sub-tree on the Z axis by elevation pixels, and draws the appropriate shadow.
Ink effects: Material shows ink effects implemented by InkFeatures like InkSplash and InkHighlight below its children.
It is also responsible of providing default styles for your Texts (that's why you're seeing the yellow underline).
Still, remember that you're making apps for mobile clients, therefore, you should be using some of the best practices that MaterialApp and CupertinoApp bring out of the box, even if you decide to take your own path inside the app, using your own custom Widgets, etc

How to disable animation at the edges of PageView?

I want users to scroll between pages in PageView, but I don't want to show them an animation when they try to scroll before first and after last page. I can switch between colorful animation, black animation and no scrolling, but I could not find any possibility to disable the animation at all.
If there is no such possibility, how can I change the color of that animation or make it transparent at least?
Based on your screenshot, I can say that you are using BouncingScrollPhysics for your PageView. This behavior is commonly used by iOS devices. Nonetheless, I have also reviewed the entire source code you have provided here.
What went wrong
You have added PageView without accompanying it with a Scaffold or Material widget at the top level that's why the background behind the children of the PageView is color black.
https://dartpad.dev/c709e410d0a68248ac5b387b3bc6af93
From the documentation:
Scaffold implements the basic material design visual layout structure.
Without this widget, you'll notice that your app may occupy the entire screen of your device, including the notification bar, because it (PageView) does not know where is the status bar is located in the screen.
What you can do
I noticed that all of the children added inside the PageView has individual Scaffold and AppBar, it's not really necessary to nest scaffolds and you may want to use TabBarView instead of PageView, and let the parent widget handle the AppBar changes via TabController.
But if you think it'll cost you too much effort to refactor, feel free to review the following options that require minimal changes which will suit your needs:
Option 1. You can wrap your widget inside a Scaffold widget.
https://dartpad.dev/4620ff91444353f5e000d2063594bd96
Option 2. Given that nesting Scaffold widgets is not a good practice, you can just use the plain Material widget to wrap your PageView with children wrapped with Scaffold widget.
https://dartpad.dev/43f8730e5592ce1f96193fc01f08a29c
These solutions will change the background color of the PageView from black to white.
Option 3. If you really want to get rid of the animation, the easiest way to hack it is changing your scroll physics:
physics: ClampingScrollPhysics(),
However, this still has a glowing or ripple effect when you try to swipe at the end of the screen.
To further get rid of this effect, I'll share with you these SO answers:
How to remove scroll glow? (works for Android)
How to remove overscroll on ios? (works for iOS)
Further reading
https://api.flutter.dev/flutter/widgets/ScrollPhysics-class.html
https://medium.com/flutter-community/custom-scroll-physics-in-flutter-3224dd9e9b41