I have a ListView item that has a dynamic height, affected by the text content. This is a simple Column with two text widgets.
When wrapping the Column in a Row and adding an Image, I want the image to expand vertically (but fixed width) to match the automatic height of the text.
However, I cannot use CrossAxisAlignment.stretch on the Row as it requires a fixed height.
How can I have my image, expand/shrink based on the text content beside it?
A Stack will automatically wrap unpositioned children. You can use this to your advantage:
import 'package:flutter/material.dart';
void main() => runApp(App());
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: ListView(
children: <Widget>[
Stack(
children: <Widget>[
Positioned(
left: 0,
top: 0,
bottom: 0,
width: 100,
child: Container(color: Colors.orange), // replace with your image
),
Padding(
padding: EdgeInsets.fromLTRB(116, 16, 16, 16),
child: Text('Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo'),
)
],
),
],
)
),
);
}
}
Related
I'm trying to create a BEM spacing helper mixin that contains the name of the screen in the class name. An example output: .marSm0 .marSm0__t .marSm0__b .marSm0__x
$emMd0: 1em !default;
$emMd1: 1.5em !default;
$emMd2: 2em !default;
$emMd3: 4em !default;
$emMdSpacing: ($emNone, $emMd0, $emMd1, $emMd2, $emMd2 );
#mixin spacingHelper($screenSize, $spacingValues){
#each $space in $spaceValues {
.mar#{screenSize}#{$space} {
margin: #{$space}rem;
}
.mar#{screenSize}#{$space}__x {
margin-left: #{$space}rem;
margin-right: #{$space}rem;
}
.mar#{screenSize}#{$space}__y {
margin-top: #{$space}rem;
margin-bottom: #{$space}rem;
}
.mar#{screenSize}#{$space}__l {
margin-left: #{$space}rem;
}
.mar#{screenSize}#{$space}__r {
margin-right: #{$space}rem;
}
.mar#{screenSize}#{$space}__b {
margin-bottom: #{$space}rem;
}
.mar-#{screenSize}#{$space}__t {
margin-top: #{$space}rem;
}
.pad#{screenSize}#{$space} {
padding: #{$space}rem;
}
.pad#{screenSize}#{$space}__x {
padding-left: #{$space}rem;
padding-right: #{$space}rem;
}
.pad#{screenSize}#{$space}__y {
padding-top: #{$space}rem;
padding-bottom: #{$space}rem;
}
.pad#{screenSize}#{$space}__l {
padding-left: #{$space}rem;
}
.pad#{screenSize}#{$space}__r {
padding-right: #{$space}rem;
}
.pad#{screenSize}#{$space}__b {
padding-bottom: #{$space}rem;
}
.pad#{screenSize}#{$space}__t {
padding-top: #{$space}rem;
}
}
}
The problem I'm having is that the $screenSize mixin argument isn't working in the each loop. How do I fix this? I'm sure if the each loop is having a scope issue. Code
Ignore for question validation
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin quis vehicula tellus, id ultrices massa. Suspendisse dignissim in odio non rutrum. Vestibulum dapibus eget eros at aliquet. Quisque vitae vulputate massa, ac laoreet orci. Vestibulum vestibulum ante quis eros sollicitudin euismod. Cras eget orci turpis.
I am trying to create a UI where the upper section is an image inside clipped view and the bottom section is some text content.
I have tried Expanded and wrapped SingleChildScrolLView with Expanded Widget and I got a white screen.
var DetailsScreenBottomPart = SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: EdgeInsets.all(18.0),
child: Row(
children: <Widget>[
Text('Basic Information'),
Spacer(),
Text('See all')
],
)),
Container(
padding: EdgeInsets.symmetric(horizontal: 18.0, vertical: 20.0),
child: Text(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Urna porttitor rhoncus dolor purus non enim praesent. Tristique senectus et netus et malesuada. Justo laoreet sit amet cursus sit. Nunc sed blandit libero volutpat. Donec enim diam vulputate ut pharetra sit amet. Lacus luctus accumsan tortor posuere. Mauris nunc congue nisi vitae suscipit. Commodo nulla facilisi nullam vehicula ipsum a. Fermentum posuere urna nec tincidunt praesent semper feugiat nibh sed. Ultrices sagittis orci a scelerisque. Enim nulla aliquet porttitor lacus luctus accumsan tortor posuere ac. Consequat id porta nibh venenatis. Viverra mauris in aliquam sem fringilla ut morbi. Habitasse platea dictumst vestibulum rhoncus est pellentesque elit. Sollicitudin aliquam ultrices sagittis orci a scelerisque. Eget nunc lobortis mattis aliquam faucibus purus in massa tempor. asgdsgdsgfdsgsdfgsdgsdgsdgfsd asgsdhsdhsdh ghsh sfh sfh fsgh shg sfdh fsh sfgh j dfjsfh sfgj dfgj dfgj dfg jdfjg dfj dfjgdfj dfj dfgj d'),
),
],
));
The output i want is pretty simple but since I started flutter today, I am getting a little confused and overwhelmed by the availibility of Widgets, can I scroll the bottom half of the screen and keep the top half static? is this even possible in flutter.
You need to use Column with 2 Expanded Child. Inside your second child keep the scrollable views.
eg :
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(
flex: 1,
child: Container(),
),
Expanded(
flex: 1,
child: Container(
width: double.infinity,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(height: 100, child: Text("Item 1")),
Container(height: 100, child: Text("Item 2")),
Container(height: 100, child: Text("Item 3")),
Container(height: 100, child: Text("Item 4")),
Container(height: 100, child: Text("Item 5")),
Container(height: 100, child: Text("Item 6")),
Container(height: 100, child: Text("Item 7")),
Container(height: 100, child: Text("Item 8")),
Container(height: 100, child: Text("Item 9")),
Container(height: 100, child: Text("Item 10")),
],
),
),
),
)
],
));
}
/*
Simply wrap that widget into Expanded and inside expanded a child SingleChildScrollView.
*/
return Scaffold(
body: Container(
child: Column(
children: <Widget>[
//This Container will remains constant
Container(
height: 300,
color: Colors.black,
),
Expanded(
child: SingleChildScrollView(
//This is Scrollable Container
child: Container(
height: 400,
color: Colors.blue,
),
),
)
],
),
),
);
I have a container and an element withing it.
<div id="container">
<div class="myEm">
...
</div>
</div>
I need to assign width and hight to that element. It should be a square. I can calculate the width relative to the parent container, but how do I pass the same value to the height:
#container .myEm {
width: calc(100% - 20px);
height: ???
}
One way is to make the myEm resize using padding bottom (or top) to maintain its aspect ratio. This makes myEm strictly a sizing element and you'll need an element inside that will size to itself. Here's what I mean for example:
myEm becomes:
.myEm {
height: 0;
padding-bottom: calc(100% - 20px);
position: relative;
width: calc(100% - 20px);
}
Then you need an element inside with the actual content:
.myEm-inner {
background: red;
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0;
}
Example: https://jsfiddle.net/dgmyxs9v/1/
You can save yourself the wrapping div by using pseudo elements.
This solution will create the same effect – but also make the div stretch to fit content – should it become too large to be contained by the square.
/* sane box-sizing */
html { box-sizing: border-box; }
*, *::before, *::after { box-sizing: inherit; }
/* box styling */
.box {
margin: 10px;
padding: 10px;
width: calc(100% - 20px);
background-color: tomato;
font-size: 10px;
float: left;
max-width: 150px;
}
/* ––––––––––––––––––––––––––––––––––––-
This is the aspect ratio part
––––––––––––––––––––––––––––––––––––- */
.box::before {
/* aspect ratio keeper – 100% = square */
padding-bottom: 100%;
float: left;
}
.box::before,
.box::after {
content: '';
display: table;
clear: both;
}
/* second box */
.box:nth-of-type(2) { background-color: olive; }
<div class="box">
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Expedita labore iusto vero perspiciatis ex fuga natus cum molestiae ut, dolor facere maxime voluptatem nesciunt nihil repellendus culpa eligendi laudantium velit.</p>
</div>
<div class="box">
<h2>Will stretch to content</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Expedita labore iusto vero perspiciatis ex fuga natus cum molestiae ut, dolor facere maxime voluptatem nesciunt nihil repellendus culpa eligendi laudantium velit. Expedita labore iusto vero perspiciatis ex fuga natus cum molestiae ut, dolor.</p>
</div>
I'm not sure what I'm doing wrong here. I'm trying to force an image to be in the same line as a few columns of text, but it keeps shifting down like in this image: http://imgur.com/Hs43rXF. The left image is what I want it to look like, but I get the right image.
I've already tried display:inline and floats, but neither works. This is my code:
.page {
margin-top:50px;
padding-left:50px;
padding-right:50px;
position:relative;
width:1000px;
height:450px;
}
.leftcolumn {
margin-top:50px;
margin-left:0px;
width: 250px;
}
.middlecolumn {
margin-left:300px;
margin-right:320px;
margin-top:50px;
float:left;
display:inline;
}
.verticalimage {
margin-right:0;
margin-top:0;
float:right;
display:inline;
vertical-align:middle;
}
<div class="page">
<div class="leftcolumn">text <br> text <br> text</div>
<div class="middlecolumn">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sit amet lorem velit. Nullam et metus eget nunc egestas laoreet et quis ligula. Vivamus lobortis sodales pulvinar. Nunc malesuada pretium ornare. Aliquam ut erat at magna pellentesque elementum. Fusce facilisis lorem et tortor euismod bibendum.</div>
<img class="rightverticalimage" src="picture1.png"/>
</div>
Thanks.
I tried this for ya. I took stuff out just so you understand the code. You can edit at your liking.
CSS
.page {
margin:5%;
width:100%;
height:450px;
}
div {
width:25%;
margin-left:3%;
float:left;
background-color:red;}
I made the BG red just so you can see where the div starts and stops
HTML
<div class="page">
<div>text <br /> text <br /> text</div>
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sit amet lorem velit. Nullam
et metus eget nunc egestas laoreet et quis ligula. Vivamus lobortis sodales pulvinar. Nunc
malesuada pretium ornare. Aliquam ut erat at magna pellentesque elementum. Fusce facilisis lorem
et tortor euismod bibendum.</div>
<div>
<img class="rightverticalimage" src="picture1.png"/>
</div>
</div>
Put the IMG in a div to help control it better.
Id also download FIREBUG onto Firefox cuz it helps with that stuff.
You're mixing a couple of different methods here. Firstly as you may have noticed with your leftcolumn, if you make a div display:inline it won't hold its width. This is because in order to render with a width or margins, an element must be block level (which divs are by default). Additionally, setting the left margin on the middlecolumn with the left div already there will set its left hand side to be at 550px within the container (250 for the leftcolumn and an additional 300 for left margin), margins and widths are cumulative.
So then two ways to do this are (I've left out your extra margins for brevity):
Using floats:
.leftcolumn
{
width: 250px;
float:left;
}
.middlecolumn
{
width: 250px;
float:left;
}
This will leave the two divs as block elements allowing them to behave as they normally would, setting the width on the two columns and continue the flow around them, since the image is an inline element, it will continue to flow as well. What this approach does do however is leave the container only as high as the image element since a floated element doesn't sit in the page flow in the same way.
Using display: inline-block
.leftcolumn
{
display: inline-block;
width: 250px;
}
.middlecolumn
{
display: inline-block;
width: 250px;
}
This will set the divs as inline-block allowing you to set a width on them, but rendering them as an inline element. The benefit of this is that the .page element will get the height of the divs automatically. It does, however break in ie7 since that doesn't render inline-block elements correctly.
I've intentionally left adding the width onto the image element since it will be the same across both approaches (just set display:block and float it, or set display: inline-block)
The site I'm working on will display lengthy articles on screen. The site is responsive so everything you see on screen will re-size and re-flow to accommodate different screens. Previously we had a two column layout where the articles would be in the left floated div. And a side bar of shorter content would be in the right hand floated div.
It was decided that since the right hand content was so short there was lots of wasted white space beneath it. I was asked to try and incorporate the right hand column into the left hand div so the text would wrap around it.
That part was pretty easy, I just floated the now embedded right hand column into the article and the written text wrapped around it.
See this JSFiddle:
http://jsfiddle.net/TheMonkxx/2aucA/1/
Here is the HTML for the page:
<div class="parent">
<div class="right_content" align="right"></div>
Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Maecenas vitae nunc arcu. Cras tortor velit, consectetur
quis consectetur vel, ultrices eu nisl. Pellentesque convallis orci ligula,
id pharetra mauris. Vestibulum eleifend, turpis eget commodo dapibus, diam
magna nunc auctor elit, nec molestie libero quam quis mi. Donec interdum
velit non arcu sollicitudin eu ullamcorper lectus venenatis. Vivamus at
lacus magna. Proin in diam semper urna fermentum molestie sit amet sit
amet augue. Nulla sit amet massa eu risus laoreet laoreet eget sed erat.
Aliquam quis enim in odio porta consequat. Ut egestas urna et erat iaculis
et aliquam libero auctor.</div>
Here is the CSS
.parent {
border: 1px solid green;
width: 200px;
float: right;
}
.right_content {
width: 25%;
height: 150px;
float: right;
background-color: red;
margin: 0 0 7px 7px;
}
The problem comes in when I try to add images to the article content. Since the site is responsive, I want the images to have max-width: 100% applied. However when I do that the images go 100% of the parent container and push any written content beneath the images gets pushed after the right hand column. See this fiddle:
http://jsfiddle.net/TheMonkxx/2a66J/
Here is the updated HTML for the page:
<div class="parent">
<div class="right_content" align="right"></div>
<img src="http://www.thetop22.com/wp-content/uploads/2012/01/Black-Keys-Banner-3.png"
/>
Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Maecenas vitae nunc arcu. Cras tortor velit, consectetur
quis consectetur vel, ultrices eu nisl. Pellentesque convallis orci ligula,
id pharetra mauris. Vestibulum eleifend, turpis eget commodo dapibus, diam
magna nunc auctor elit, nec molestie libero quam quis mi. Donec interdum
velit non arcu sollicitudin eu ullamcorper lectus venenatis. Vivamus at
lacus magna. Proin in diam semper urna fermentum molestie sit amet sit
amet augue. Nulla sit amet massa eu risus laoreet laoreet eget sed erat.
Aliquam quis enim in odio porta consequat. Ut egestas urna et erat iaculis
et aliquam libero auctor.</div>
And the updated CSS:
img {
max-width:100%;
}
.parent {
border: 1px solid green;
width: 200px;
float: right;
}
.right_content {
width: 25%;
height: 150px;
float: right;
background-color: red;
margin: 0 0 7px 7px;
}
Giving the image a pre-defined width fixes the layout but it causes problems for the responsive nature of the site. I also will have some articles which have images at various places in the copy, so I can't always predict an image will be beside the right hand column.
Any ideas or suggestions how I can get the desired layout and keep the responsive aspect working? Thanks!
Although this is old, I've just figured out a good and simple solution using jQuery.
CSS Part
First we need to set all the images to be small so they can fit next to the floating div. let's say 75%;
.parent img {
max-width:100%;
width: 75%;
}
jQuery Part
Then we want to reset the width of all images below the floating div:
jQuery(document).ready(function(){
var h = jQuery(".right_content").height(); //get floating div height (let's say it's dynamic).
jQuery('.parent img').each(function(){ //loop through all images in content
jQuery(this).removeAttr('style') //remove any disturbing inline styles. optional.
var p = jQuery(this).position(); //get each .wp-caption position
var top = p.top; //top position
if(top > h){ //if img is below the floating div
jQuery(this).css("width", "initial") //change img width to original (or anything you like)
}
});
});
hope it help somehow.
Without a script with which to do some calculations, you might have to settle for smaller images.
http://jsfiddle.net/2a66J/2/
img {
max-width:72%;
float: left;
}
Technically, your site isn't "responsive". It's "fluid". If it was responsive you could set fixed max-widths based on viewport size and have 100% image width for all scenarios. The minor drawback is that you aren't usually using 100% of the available viewport width for your page with a responsive design.
One way to look at this, however it is not very efficient and be very bloated if you are working with lots of images.
If what you posted on jsFiddle is all that you have to work with, then my suggestion is to add a around said article image. You will then constraint this to a percentage and either float it left or right with a secondary class.
HTML
<div class="article_image article_image_flleft"><img src="http://www.thetop22.com/wp-content/uploads/2012/01/Black-Keys-Banner-3.png"
/></div>
CSS
.article_image{
width: 50%;
}
.article_image_flleft{
float: left;
}
Fiddle:
http://jsfiddle.net/D8ELj/1/
As isherwood points out, setting various viewports at be more beneficial in the long run.