jamesblasco/layout

Advice on how to have a single row with two boxes that size with the window, one vertical scroll?

MostHated opened this issue Β· 9 comments

Hey there,
I am trying to figure out the best way to go about achieving a single row with two boxes that size with the window, one vertical scrolling?

Here is what I have:

I am wanting them to pretty much be fixed where they are in the image, but if the main windows resizes, I want them to get wider/taller to match the window. (A bit more space between them in the center would be nice, but I can figure that out later).

The biggest issue is with the right side vertical scroll. I am not sure how to add a bit more gap between each one, but even worse, when I currently reize it, it disappears completely as seen here:

https://i.imgur.com/DQzCv7K.mp4

This is my first time using your library, so I tried to Frankenstein it together from bits and pieces of the examples.

If you might be able to offer any assistance, I would greatly appreciate a push in the right direction.
Thanks,
-MH

 return Material(
      type: MaterialType.transparency,
      child: Scaffold(
        body: Container(
          decoration: BoxDecoration(
            image: DecorationImage(
              image: AssetImage("assets/images/main1.png"),
              fit: BoxFit.cover,
            ),
          ),
          child:  FluidLayout(
            child: Builder(
              builder: (context) => CustomScrollView(
                slivers: <Widget>[
                  SliverToBoxAdapter(
                      child: SizedBox(
                          height: context.fluid(40, xs: 12, s: 12))),
                  SliverFluidGrid(
                    children: [
                      FluidCell.withFluidHeight(
                          size: context.fluid(6),
                          heightSize: context.fluid(4, m: 4, s: 6, xs: 6),
                          child: CustomCard(
                              child: Container(
                                child: Center(
                                    child: Text(
                                        'Only visible in small screens')),
                              ))),
                      FluidCell.withFluidHeight(
                          size: context.fluid(6),
                          heightSize: context.fluid(4, m: 4, s: 6, xs: 6),
                          child:                    Container(
                            height: 10,
                            child: ListView.separated(
                              itemCount: 10,
                              padding: EdgeInsets.symmetric(
                                  vertical:
                                  FluidLayout.of(context).horizontalPadding +
                                      FluidLayout.of(context).fluidPadding),
                              shrinkWrap: true,
                              scrollDirection: Axis.vertical,
                              itemBuilder: (context, index) => CustomCard(
                                  color: Colors.white70,
                                  child: Container(
                                      height: 100,
                                      width: 100,
                                      child: Center(
                                        child: Text('Item'),
                                      ))),
                              separatorBuilder: (_, __) => SizedBox(
                                  width: FluidLayout.of(context).horizontalPadding),
                            ),
                          ),),
                    ],
                  ),

                ],
              ),
            ),
          ),
        ),
      ),
    );

Hello, if you want the left side to be fixed and the right one to be able to scroll you shouldn't use a CustomScrollView.

I would use a row for that

Fluid(child: Row(
crossAxisAligment =CrossAxisAlignment.strech //this will expand the height of the items at maximum
children: [
   Flexible(1, child: .......)
   SizedBox(width: 20) // Space between items
   Flexible(1, child: .......) // You add here the ListView inside
]),);

If you want the children of the ListView to fill all the height you can define a height to the widget.
With MediaQuery.of(context).size.height you get the height of the screen. Remember to subtract the top and bottom padding that you might want.

Let me know if this fits what you need

I appreciate the reply. I tried to implement what you recommended, and I am quite close to getting it. I tested using two custom cards, one for each side just to see about the movement and what not and it worked great. Though I ran into issue when trying to reimplement the list view.

If I try and reuse the list view from my post (omitting the code below)

FluidCell.withFluidHeight(
    size: context.fluid(6),
    heightSize: context.fluid(4, m: 4, s: 6, xs: 6),

I started with the Container, so that I have this below:

return Material(
      type: MaterialType.transparency,
      child: Scaffold(
        body: Container(
          decoration: BoxDecoration(
            image: DecorationImage(
              image: AssetImage("assets/images/main1.png"),
              fit: BoxFit.cover,
            ),
          ),
          child: FluidLayout(
            child: Fluid(
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  Flexible(
                      child: CustomCard(
                          child: Container(
                              child: Center(
                    child: Text('Only visible in small screens'),
                  )))),
                  SizedBox(width: 60), // Space between items
                  Flexible(
                    child: Container(
                      height: 10,
                      child: ListView.separated(
                        itemCount: 10,
                        padding: EdgeInsets.symmetric(
                            vertical:
                            FluidLayout.of(context).horizontalPadding +
                                FluidLayout.of(context).fluidPadding),
                        shrinkWrap: true,
                        scrollDirection: Axis.vertical,
                        itemBuilder: (context, index) => CustomCard(
                            color: Colors.white70,
                            child: Container(
                                height: 100,
                                width: 100,
                                child: Center(
                                  child: Text('Item'),
                                ))),
                        separatorBuilder: (_, __) => SizedBox(
                            width: FluidLayout.of(context).horizontalPadding),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );

I keep getting this error, though:

flutter: Another exception was thrown: NoSuchMethodError: The getter 'data' was called on null.

I am guessing that it has something to do with the padding? If that is correct, am I to either supposed to add values to one of the parents, or since this is no longer setup the way it was before/in the original examples (when it was in the horizontal scrolling demo) is it best to remove the FluidLayout.of parts and replace them with something else?

Thank you again for your help. I very much appreciate it!
-MH

Great progress!!
This problem it is about the BuildContext and it is a classic Flutter problem developers make.

In this line FluidLayout.of(context).horizontalPadding) you are trying to find a FluidLayout widget through a context that doesn't have e reference to a FluidLayout.

How SomeWidget.of(context) works is that it looks for the closest widget SomeWidget up on the widget parents above the context reference.
You are probably using the context of the build function and FluidLayout is a child of it, so the context can not find it.

You have to create a new context below, something like this

FluidLayout(
  child: Builder(
      builder: (context) => SizedBox(
                            width: FluidLayout.of(context).horizontalPadding)
));

In your case it is simpler as separatorBuilder creates a new context.

 separatorBuilder: (context, __) => SizedBox(
                            width: FluidLayout.of(context).horizontalPadding),
 ),

BuildContext is awesome but it is hard to understand at the beginning. Hope my explanation makes it a bit more clear.

I made the change you recommended and fired it back up but still had the same error, so I looked around a bit and noticed that in addition to the horizontalPadding within the item builder, in the EdgeInsets.symmetric() there was the other one with no ability to do a separatorBuilder, so I just changed those to hardcoded values and tried again and it looks like I should be all set now!

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

I need to do some tweaking to make things how I want them, but overall it is working just how I envisioned, so a big thanks for your assistance as well as patience. Now the fun part of learning how to use firebase to get some data in here, lol. πŸ‘

Thanks again,
-MH

Oh, I did have one last unrelated question. For the left card, it was going to be a news card, with a top row that has an image, then some text below it, and the right ones were going to be similar, just a small image on the left and then some text to the right (subject to change, depending on how it looks, of course).

So my question is, with how this is currently set up, being that it is within a FluidLayout, within the left card, if I wanted to have the image and data also be fluid to scale with the rest of it if it is moved around, would that be considered a new and separate FluidLayout setup, or would it end up being a continuation of the current FluidLayout? I want to try and make it as "proper" and professional as I can and do it whatever would be considered the ideal way to do it, I just, unfortunately, am not yet experienced enough to make that determination when it comes to the widget tree, context, and drawing performance, etc.

If you have a spare minute and would not mind simply sharing your thoughts on what you think would be a good way to go about it, that would definitely help get me going on this next step!
Thanks,
-MH

I would nest another FluidLayout inside, as I would like the padding and the breakpoints to match the the size of that left card container.

That definitely makes sense. I will go ahead and do that then. You have been above and beyond helpful. I will be sure to share this package anytime I hear of anyone working with Flutter. : D πŸ‘

Thanks,
-MH

Thank you for your kind words @MostHated.
Don’t doubt to come back to me if you have any questions related to this package or Flutter in general πŸ™‚

Sorry to bother you again. I always try to search as much as I can before asking something, but I had a few quick things I have come across that I could use a quick hand with if you have a few minutes?

One of them I feel like they should be fairly easy, but I just can't seem to get a result.
For the ones labeled 1 in the image above, I can't seem to figure out how to make any sort of gap there that will stay consistent relative to the overall height of the window.
^ I figured this (the two "1" arrows) one out while typing the question by wrapping the row I had in a container, then it let me use : margin: EdgeInsets.symmetric(horizontal: 0, vertical: 20).

For the item labeled 2 in the image above, when I try to make it smaller, the image shrinks, but then the text simply begins to clip and get cut off and as shown there, it begins to overflow.

At first, I was thinking it would be neat to shrink the text along with the image, but I am not sure that is the best idea. I would not mind trying though if there is a way that is not to difficult to implement, just in case I happen to like it? (Is that something in which your FluidLayout.of(context).fluidBreakpoint could be used? Is this "universal" in its application?). If not, is text wrapping able to occur within those boxes while using Fluid?

On the inverse of that, both boxes do shrink, but they only ever expand to X amount and I feel silly for not being able to spot what is keeping them from expanding more along with the window.

If it would help to see the code again, I tried to do a bit of refactoring to make things a bit easier to work with, so here it is as it stands now.

Widget leftCard() {
      return FluidLayout(
          child: Fluid(
        child: Container(
//          height: MediaQuery.of(context).size.height * .90,
          child: Column(children: [
            Container(
                child: Image(
              image: new AssetImage('assets/images/searcher2.png'),
              fit: BoxFit.cover,
            )),
            SizedBox(height: 15),
            Container(
              child: Row(
                children: [
                  Column(children: [
                    Text(
                      'Welcome to the Searcher v0.1 beta release!',
                      style: TextStyle(fontSize: 20),
                    ),
                    Text('Click here to view the full message', style: TextStyle(fontSize: 15)),
                  ])
                ],
              ),
            ),
          ]),
        ),
      ));
    }

    Widget rightCard() {
      return FluidLayout(
        child: Fluid(
            child: Container(
                // Trying to make it so the corners were always rounded in the parent box, but it's not 
                // https://i.imgur.com/AcRh5RP.png
                decoration: BoxDecoration(
                    border: Border.all(
                      color: Colors.transparent,
                    ),
                    borderRadius: BorderRadius.all(Radius.circular(20))),
                child: ListView.separated(
                  itemCount: 10,
                  padding: EdgeInsets.symmetric(horizontal: 0, vertical: 0),
                  shrinkWrap: true,
                  scrollDirection: Axis.vertical,
                  separatorBuilder: (context, __) => SizedBox(
                    width: FluidLayout.of(context).horizontalPadding,
                    height: 8,
                  ),
                  itemBuilder: (context, index) => CustomCard(
                      color: Colors.white12,
                      child: Container(
                          height: 50,
                          width: 200,
                          child: Center(
                            child: Text('Item'),
                          ))),
                ))),
      );
    }

    return Material(
      type: MaterialType.transparency,
      child: Scaffold(
        body: Container(
          decoration: BoxDecoration(
              image: DecorationImage(
            image: AssetImage("assets/images/main1.png"),
            fit: BoxFit.cover,
          )),
          child: FluidLayout(
              child: Fluid(
                  child: Container(
            margin: EdgeInsets.symmetric(horizontal: 0, vertical: 20),
            height: MediaQuery.of(context).size.height - 160,
            child: Container(
              height: MediaQuery.of(context).size.height,
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: [
                  Flexible(flex: 1, child: CustomCard(color: Colors.white10, child: leftCard())),
                  SizedBox(width: 80), // Space between items
                  Flexible(flex: 1, child: rightCard())
                ],
              ),
            ),
          ))),
        ),
      ),
    );