Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

context.widthPx origin? #3

Closed
MostHated opened this issue Jun 20, 2020 · 10 comments
Closed

context.widthPx origin? #3

MostHated opened this issue Jun 20, 2020 · 10 comments

Comments

@MostHated
Copy link

Hey there,
When using context.widthPx, where is that size actually coming from? I am trying to put an AnimatedContainer inside my Expanded widget, as I am using an event to resize two Expanded containers on three possible conditions. Both start off at 50/50 flex size, then on the second condition it changes to 25/75, the last condition it's 75/25. It worked well without the Animated container, but the size transition is instant and I would prefer to have it animate.

I was hoping that this package might be able to help somehow, but I am not quite sure where the size of context.widthPx is coming from? Is it the size of wherever it happens to be in the widget tree at the time it is being called, the size of the topmost parent of that particular widget up to the most recent build method, or is it the size of the screen itself?

This is essentially how things are setup at the moment:

  Flex(
    direction: Axis.horizontal,
    crossAxisAlignment: CrossAxisAlignment.end,
    children: <Widget>[
      Expanded(  // <---  I would like to get the current width of this
        flex: (target[expController.target]["newsWidth"]),
        child: AnimatedContainer(
          width: ?, // <-- and use it here
          duration: Duration(milliseconds: 500),
          curve: Curves.fastOutSlowIn,
          child: NewsMainHome(),
        ),
      ),
      Spacer(flex: target[expController.target]["spacer"]),
      Expanded(
        flex: (target[expController.target]["changeLogWidth"]),
        child: AnimatedContainer(
          width: ?, // Set to parent size
          duration: Duration(milliseconds: 500),
          curve: Curves.fastOutSlowIn,
          child: ChangeLogList(),
        ),
      ),
    ],
  ),

It would be nice to be able to set the AnimatedContainer width to the size of the parent Expanded width so it will animate the size transition when the Expanded flex value changes from the event, but I have yet to find a decent way to go about it.

Thanks,
-MH

@esDotDev
Copy link
Contributor

esDotDev commented Jun 20, 2020

Context sizes will always be the entire screen size.

What you want here is a Layout builder:

Expanded(
child: LayoutBuilder(
    builder: (_, constraints){
        //Have fun with constrains.maxWidth :)
    }  
  }
)

Tho, tbh I'm not sure is how you want to do it. When you change the flex, the Expanded parent will change. Trying to manually animate the child, when the parent will be snapping into place... doesn't seem like it will work properly.

You would use LayoutBuilder to make decisions inside the content area, about which content you hide/show based on available size, but not in order to control the actual size.

What you actually want to do is animated your Flex values. If your flex transitioned from 75 > 50 using a tween, the child container would just animate naturally.

Something more like this would probably work:

var leftFlex = 75;
return TweenAnimationBuilder<int>(
  tween: Tween(begin: 50, end: leftFlex),
  duration: Duration(milliseconds: 700),
  builder: (_, value, __){
    return Row(
      children: [
        Expanded(flex: value, child: leftContent),
        Expanded(flex: 100 - value, child: rightContent),
      ],
    )
  },
)

Now, when you set leftFlex to whatever, the both content areas will animate, with right taking up the remaining space. Don't be thrown off by the 'begin' param, it is only used once on first load of the widget.

But this is more a StackOverflow question, so post it there so I can get some points :)

@esDotDev esDotDev reopened this Jun 20, 2020
@MostHated
Copy link
Author

MostHated commented Jun 20, 2020

I definitely appreciate the reply. Also, no problem, I feel you on the points, lol. I will post the original question there now and send you the link, and then make my real reply there. I suppose I should refactor it a bit to have it just be about the parts not specific to your package?

@MostHated
Copy link
Author

Here it is, if you want to put your answer there. https://stackoverflow.com/questions/62487312/obtaining-parent-size-to-use-within-child

@esDotDev
Copy link
Contributor

Haha, somone beat me to it. All good. Good luck!

@MostHated
Copy link
Author

Hey man, I appreciate you having helped out earlier. I wanted to share an update, just in case you happened to be interested. If not, well, it's happening anyways.

After what you mentioned, I set out to see what I could come up with, but unfortunately, mostly due to how my setup is I could not make use of the TweenAnimationBuilder, at least not without a bunch of random intermittent issue. Once I started looking into it more, it made sense, though when I checked out the comments on it:

The [TweenAnimationBuilder] takes full ownership of the provided [tween]
instance and mutates it. Once a [Tween] has been passed to a
[TweenAnimationBuilder], its properties should not be accessed or changed
anymore to avoid interference with the [TweenAnimationBuilder].

The key components of my setup pretty heavily rely on accessing and changing of values, so it seems it just wasn't fit for this particular situation. I tried out the other things you and the other fella on StackOverflow mentioned, and I could not get very good results from those either. I took a step back, got some coffee and tried to rethink my approach. I was getting stuck on some things because this widget is wrapped in an event listener, then others due to the flex/expand objects, which I thought were pretty necessary to what I was trying to accomplish. Turns out they were not, and actually ended up being the thing that was standing in my way, lol.

Here is what I ended up with (and context.widthPx actually came in quite handy, lol):

  expandController(bool value, String type) {
    if (value && type == "changelog") {
      numOpened++;
    } else if (!value && type == "changelog") {
      numOpened--;
    } else if (value && type == "news") {
      numOpened--;
    } else if (!value && type == "news") {
      numOpened++;
    }

    if (numOpened == 0) {
      expController.expandTarget(ExpandTarget.NONE);
    } else if (numOpened > 0) {
      expController.expandTarget(ExpandTarget.CHANGELOG);
    } else if (numOpened < 0) {
      expController.expandTarget(ExpandTarget.NEWS);
    }
    setState(() {});
  }

  Map<ExpandTarget, dynamic> target = {
    ExpandTarget.NONE: {"newsWidth": 50, "spacer": 5, "changeLogWidth": 50},
    ExpandTarget.CHANGELOG: {"newsWidth": 25, "spacer": 1, "changeLogWidth": 75},
    ExpandTarget.NEWS: {"newsWidth": 75, "spacer": 1, "changeLogWidth": 25}
  };

  Container(
	margin: EdgeInsets.fromLTRB(0, 22, 0, 30),
	padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
	height: MediaQuery.of(context).size.height - 122,
	child: EventSubscriber(
	    event: expController.valueChangedEvent,
	    handler: (context, args) => Row(
	          crossAxisAlignment: CrossAxisAlignment.end,
	          children: <Widget>[
	            AnimatedContainer(
	              width: (((target[expController.target]["newsWidth"]) * 0.1) * (context.widthPx * 0.089)),
	              duration: dur,
	              child: NewsMainHome(),
	            ),
	            Spacer(flex: target[expController.target]["spacer"]),
	            AnimatedContainer(
	              width: (((target[expController.target]["changeLogWidth"]) * 0.1) * (context.widthPx * 0.089)),
	              duration: dur,
	              child: ChangeLogList(),
	            )
	          ],
	        )),
	  )

It's not quite as clean and easy to get the sizes and distance between the two boxes the way I wanted them vs using the flex values, but it just needs a tad more tweaking. Here was the end result:

https://i.imgur.com/mM2S5Uv.gifv

I have been going through and cleaning up a lot of my MediaQuery and other similar items, and am now using this package in a number of places, so a big thanks for creating the package, and thanks again for the assistance. I really do appreciate it. 👍

-MH

@esDotDev
Copy link
Contributor

esDotDev commented Jun 22, 2020

Oh nice. but fwiw I'm sure TwAnimBuilder would work for this. When you change the endValue a new tween is generated internally. You don't change the tween directly, but you can change the endValue as many times as you need to produce infinite new tweens.

Something like:

enum ExpandTarget { None, News, ChangeLog }
double newsFlex = 50;

void setTarget(ExpandTarget value)
{
    // Changing newsFlex and calling setState will trigger the Tween to run
    setState((){
        newsFlex = 50;
        if(value == ExpandTarget.News) newsFlex = 75;
        else if(value == ExpandTarget.ChangeLog) newsFlex = 25;
    });
}

void build(){
  return TweenAnimationBuilder<int>(
    tween: Tween(begin: newsFlex, end: newsFlex),
    duration: Duration(milliseconds: 700),
    //Value tweens to 25, 50 or 75, and represents the current newsFlex value as its being animated
    builder: (_, value, __){
      return Row(
        children: [
          Expanded(flex: value, child: News()),
          //The flex of the ChangeLog, is simply 100 - currentNewsFlex
          Expanded(flex: 100-value, child: ChangeLog()),
        ],
      )
    },
  );
}

You can call setTarget all day long, and it will just tween back and forth.

@MostHated
Copy link
Author

I definitely had tried just changing the values in the tween, it mostly just ended up going red here and there. It could possibly be because it was wrapped in that eventlistener, which is capable of rebuilding the widget upon receiving an event, which might have interfered with the builder trying to execute the tween?

@esDotDev
Copy link
Contributor

Hmm, looking into it a bit deeper, it seems TAB has issues tweening integers. You can make it work easily though by tweening to .75 instead of 75 and then just doing:

Expanded(flex: (.75 * 100).toInt())

@esDotDev
Copy link
Contributor

Ahh, figured it out. Use StepTween instead of Tween when using Integers. Should work like a charm :)

@MostHated
Copy link
Author

MostHated commented Jun 22, 2020

Nice, I will definitely give that a go. I also just came across this package earlier today ResponsiveFramework and since it was so easy to implement, I decided to give it a try. It made resizing the application overall really nice with the breakpoints, but ended up making it when the main window is resized, the boxes themselves feel way better when resizing for some reason. Between that and if I am able to get the flex back, that could do the trick to make it perfect. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants