Dynamically position widget in stack Flutter - flutter

I am trying to create a view that consist of a background image with widgets positioned dynamically in certain places on this image, each widget will have an x and y that needs to be calculated for different screens and for different image sizes.
what i did so far was showing the image in a stack and made a list of widgets where each widget type is being checked then create a flutter widget that corresponds with it adding it to this list and displaying it over the image in the stack, but i am looking for a cleaner way to create this behavior, also when rotating the screen the widgets are not being placed in a correct position,
Thank you for your time.

You can do something like:
Stack(
children: [
Image.asset('YOUR IMAGE HERE', fit: BoxFit.cover), // this is your bg image,
..List.generate(imagesCollection.length, (index) {
// you could encapsulate all this logic in a separate widget
var img = imagesCollection[index];
var r = Random();
// make sure to stay within the bounds of your screen
var screenWidth = MediaQuery.of(context).size.width;
var screenHeight = MediaQuery.of(context).size.height;
var randomX = r.nextInt(screenWidth);
var randomY = r.nextInt(screenHeight);
// before you position the image, check that is within the bounds
// check if the randomX - IMAGE_WITH is less than the screen width, same for the height
return Positioned(
top: randomY,
left: randomX,
child: Image.asset(img, width: IMAGE_WIDTH, height: IMAGE_HEIGHT)
);
}
]
)
Something around those lines.

Related

Get size of screen without bottom navigation bar height

So the basic scaffold in flutter has appbar, body and bottom bar.
in my bottom navigation bar I have 3 items:
Page 1 (Editor Page)
page 2 (Stickers)
page 3 (Text Customization Page)
Each of these pages have their own scaffolds.
Editor page has a widget called LayoutCanvas which is something like:
Widget build(BuildContext context) {
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
CanvasModel.of(context).init(canvasKey!);
});
return Container(
Inside init:
void init(GlobalKey canvasKey) {
_canvasKey = canvasKey;
final context = _canvasKey.currentContext;
if (context == null) return;
final bounds = context.findRenderObject()!.paintBounds;
final screenHeight = MediaQuery.of(context).size.height;
final screenWidth = MediaQuery.of(context).size.width;
var canvasHeight = screenHeight * 0.7;
var canvasWidth = layout.aspectRatio * canvasHeight;
Issue:
As you can see I'm taking 0.7 or 70% of the screen height as the canvas height and calculating the rest from there. But 70% is quite small for something like an editor canvas. But if I make it 80% some of the editor is getting cut by the bottom navigation bar.
Maybe the screenHeight is not taking the bottom navigation bar height into consideration?
I either need to make it dynamic or I need to subtract the bottom nav height from screenHeight.
aspectRatio:
double get aspectRatio => isInitialized ? height / _layout!.height : 0;
How can I solve this issue?
To get the maximum available height you need to distract some values from MediaQuery.of(context).size.height. Assuming that you have a top AppBar and a BottomNavigationBar, you can use this formula:
MediaQuery.of(context).size.height - // total height
kToolbarHeight - // top AppBar height
MediaQuery.of(context).padding.top - // top padding
kBottomNavigationBarHeight // BottomNavigationBar height
you can use MediaQuery.of(context).size.width and
MediaQuery.of(context).size.height

Flutter web show popup menu on hover and remove on mouse exit

Is there a way to achieve popup menu on header which expands on hover and closes on mouse exit
You can use the MouseRegion widget to determine the hover changes. Popup in the sense, could you explain what exactly you want to achieve? Some would be possible some wouldn't be. I hope you just need to expand the menu button on hover, which you can use an AnimatedContainer for the menu, warp it with MouseRegion widget, declare a variable that says the width, and height of AnimatedContainer widget. MouseRegion has onEnter and onExit functions, onEnter is when the container has hovered and onExit is when the user stops hovering the container. During onEnter you can increase the width and height and during onExit, you can set it to default.
double _animatedContainerHeight = 30; //Default height
double _animatedContainerWidth = 30; //Default width
MouseRegion(
onEnter: (value) {
setState(() {
_animatedContainerHeight = 50; //OnHover height
_animatedContainerWidth = 50; //OnHover width
});
},
onExit: (value) { setState(() {
_animatedContainerHeight = 30; //Return back to normal height
_animatedContainerWidth = 30; //Return back to normal width
});
},
cursor: SystemMouseCursors.click, //Cursor type on hover
child: AnimatedContainer(
duration: Duration(milliseconds: 200),
height: _animatedContainerHeight, //Animation height control
width: _animatedContainerWidth, //Animation width control
),
)

Why is setting the y position of an object as the height of UIScreen divided by 2 not placing it at the top of the screen?

I am currently creating a rhythm game and want to place a "beat" object (a circular object) at the top of the screen when the game starts. This object is an SKShapeNode, and to set its y position, I used UIScreen.main.bounds.size.height / 2 (divided by 2 since the origin is in the middle of the screen). However, this results in the object placed around halfway from the edge of the screen to the middle of the screen like this.
In the class I declare:
let screenRect = UIScreen.main.bounds
var screenWidth: CGFloat!
var screenHeight: CGFloat!
Then later initialize screenWidth and screenHeight like so:
screenWidth = screenRect.size.width
screenHeight = screenRect.size.height
Finally, the position is set as:
self.position = CGPoint(x: 0, y: screenHeight / 2)
In the initializer
Why is the object not at the top of the screen and how would I fix it?
Okay, I found my problem. I just needed to add the line scene.size = view.bounds.size to my GameViewController. This made the scene size fit the screen size, therefore, correcting the values.

Flutter - Controllable Sprite/Gif Animation on Overlay

I want to show some animation when user tap on the screen. The animation need to be controllable too as it needs to be reset after each tap.
What I have tried:
1. Show a Gif image in Overlay.
RenderBox renderBox = context.findRenderObject();
var size = renderBox.size;
var offset = renderBox.localToGlobal(Offset.zero);
_myGif = Image.asset('images/mygif.gif', width: 100, height: 100,);
return OverlayEntry(
builder: (context) => Positioned(
left: offset.dx - 50.0 + size.width/2,
top: offset.dy - 50.0 + size.height/2,
child: Container(
child: _myGif
),
)
);
Problem: The Gif animation is not controllable. The animation also appears to be played from random frames and end at random frames each time.
Use third party widget (gif_ani)
_animationCtrl = GifController(vsync: this, duration: new Duration(milliseconds: 1000), frameCount: 38);
_mygifAnimation = GifAnimation(
width: 100.0,
height: 100.0,
image: AssetImage('images/mygif.gif'),
controller: _animationCtrl,
);
Problem: It only works when it's not on an Overlay. When the GifAnimation is added as a child in Overlay it doesn't display at all.
Use Flame to run sprite sheet
Problem: AnimationAsWidget doesn't fit my requirement as I need to control the animation. Other ways would make my code too complex as I'm not building a game.
Is there any solution on this? Thank you in advance.

How to create a table with fixed length inside a scrollView in Appcelerator Titanium?

I'm trying to add some imageViews and a tableView into scrollView in Titanium. I want the scrollView to be scrollable but not the tableView inside, so I set tableView.scrollable to false. However, even if the height of the scrollView exceeds the height of the screen, it is not scrollable. Since it's not encouraged to put a tableView inside a scrollView, I'm wondering if there is a better way to create a table with fixed length inside a scrollView in Titanium?
The following is my code:
var view = Ti.UI.createScrollView({
contentWidth:'auto',
contentHeight:'auto',
top:0,
showVerticalScrollIndicator:true,
showHorizontalScrollIndicator:true,
});
var imageview1 = Ti.UI.createImageView({
image: "../images/headers/gscs_logo.png",
height: 80,
left: 10,
right: 10,
top: 10,
});
var imageview2 = Ti.UI.createImageView({
image: "../images/headers/wellness_logo.png",
height: 80,
left: 10,
right: 10,
top: 90,
});
view.add(imageview1);
view.add(imageview2);
var tableview = Ti.UI.createTableView({
data: [{title:'a'}, {title:'b'}, {title:'c'}, {title:'d'}, {title:'e'}, {title:'f'}, {title:'g'}],
top: 180,
scrollable: false,
});
view.add(tableview);
Ti.UI.currentWindow.add(view);
This is the window I got (StackOverflow does not allow new users to post images, sorry).
This is the window I want. The table has fixed number of rows and its parent view can be scrolled.
I have also tried to set currentWindow.layout to "vertical", but that failed since neither the scrollView nor the tableView would show up.
Thank you for your patience and help!
After looking at Kitchen Sink, Titanium's demo app, I figured out how to do this: just set tableview.style to Titanium.UI.iPhone.TableViewStyle.GROUPED, and and set the imageView as tableview.headerView.
var imageview = Ti.UI.createImageView({
image: "../images/headers/bakerinstitute_logo.png",
height: 100,
left: 40,
right: 40,
top: 10,
});
var tableview = Ti.UI.createTableView({
data: [{title:'a', header:'first one'}, {title:'b'}, {title:'c'}, {title:'d'}, {title:'e'}, {title:'f'}, {title:'g'}, {title:'h'}, {title:'i'}, {title:'j'}, {title:'k', header:'last one'}],
style:Titanium.UI.iPhone.TableViewStyle.GROUPED,
backgroundColor:'transparent',
rowBackgroundColor:'white',
headerView: imageview
});
Ti.UI.currentWindow.add(tableview);
You should check out the UICatalog sample code provided by apple. There are many views, and some of them look like the one you provided a link for. Hope that Helps!