Xcode Auto Layout: Can't resize window - xcode

What I want to achieve:
Custom View 1
aligned at the top
fixed height = 20px
width = window width
Horizontal Split View
just below the custom view
width = window width
height = as large as possible
Custom View 2
aligned at the bottom
fixed height = 20px
width = window width
It's a really simple layout: a header and a footer at the top and bottom of the window, and a split view in between with some content to the left and to the right that should resize with the window. However, Apple designed the Auto Layout manager so poorly, I can't seem to get this to work. (I've fumbled around for about three hours now!)
The problem is: As soon as I give the custom views a fixed height, the window height is locked, I can't resize it vertically any more. I'm trying to do this with the following constraints:
Custom View 1
Constraints
height = 20px
Custom View 2
height = 20px
Constraints
Leading horiz space from Custom View 1 to Superview = 0
Leading horiz space from Custom View 2 to Superview = 0
Leading horiz space from Split View to Superview = 0
Trailing horiz space from Custom View 1 to Superview = 0
Trailing horiz space from Custom View 2 to Superview = 0
Trailing horiz space from Split View to Superview = 0
Top vert space between Custom View 1 and Superview = 0
Vert space between Custom View 1 and Split View = 0
Vert space between Custom View 2 and Split View = 0
Bottom vert space between Custom View 2 and Superview = 0
Top vert space between Custom View 2 and Superview = 344px (!)
The last line is added by Xcode, and I can't delete it. Of course, this is responsible for the fixed vertical layout. How can I get rid of it???

OK, I finally figured it out.
I had to leave IB's redundant constraint in, but give it a priority of 1. IB had given it a priority of 1000, always overriding my constraint.

Every view needs to have enough constraints for the layout system to calculate the position (x and y) and the size (width and height). If the system does not have enough information to calculate these properties, the layout is considered ambiguous. Interface Builder in Xcode will not let you create an ambiguous layout, so it will add constraint to ensure a fully constrained layout.
Based on your information, it seems as though subview2 is sufficiently constrained. However, I think maybe you haven't set the height of the view as a constraint. The frame you set for a view is ignored by the layout system. That would introduce ambiguity. Try adding a height constraint to subview2.

Related

Technique for drawing theme element (i.e. how to not stretch draw)?

I'm looking at drawing a custom theme element onto a device content.
For example's sake, i will use the HeaderItem from the Windows XP header/listview:
(18×18 px)
Which we can blow up to see a little easier:
Note: I am not using the Theme API, nor am i asking about using the Theme API.
If i have my bitmap, like the one above, how can i draw it in practice?
Stretch draw ruins the style
The important problem that needs solving is how to maintain the important details. You can see the actual Windows XP Header draws the right-edge vertical line nice and crisp:
But if i were to blindly StretchBlt the image, the details become fuzzy:
The issue also happens with theme elements with crisp horizontal feature when the image is stretched vertically. In this case it also messes up the vertical gradient. But some other element have it even more pronounced.
So what is the technique that can be used to address this?
Should i cut 6 px off the top, left, bottom, and right?:
And then rather than drawing 1 image, i draw nine?:
And draw them with various horizontal or vertical stretch rules depending where it is?:
Unstretched
Horizontally stretched
Unstretched
Vertically stretched
Horizontally and vertically stretched
Vertically stretched
Unstretched
Horizontally stretched
Unstretched
This must be a solved problem already; since Windows already solved it, and who knows how many more Widget libraries that support themes.
Microsoft's solution to this problem can be reverse engineered by looking at the NormalBlue.ini file inside Luna.msstyles. Looking at the entry for Header.HeaderItem:
NormalBlue.ini:
[Header.HeaderItem]
bgtype = imagefile
SizingMargins = 8, 8, 3, 4
ContentMargins = 3, 0, 0, 0
ImageFile = Blue\ListViewHeader.bmp
imageCount=5
imageLayout=vertical
sizingType = tile
transparent=true
transparentcolor=255 0 0
FillColorHint = 250 248 243; Average fill color (light beige)
AccentColorHint = 252 194 71; Rollover hilite color (orange)
First we see it references the \Blue\ListViewHeader.bmp:
ImageFile = Blue\ListViewHeader.bmp
Which is:
And then there's the magic piece:
SizingMargins = 8, 8, 3, 4
This corresponds to TMT_SIZINGMARGINS:
TMT_SIZINGMARGINS: The margins used for sizing a non-true-size image.
where you can see some more hints in TmSchema.h:
//---- rendering MARGIN properties ----
TM_PROP(3601, TMT, SIZINGMARGINS, MARGINS) // margins used for 9-grid sizing
"Margins used for 9-grid sizing". This is a reference to the idea that you split up the image into 3x3 grid, and size the chunks independently as appropriate.
And the final piece is the documentation of the MARGINS type in UxTheme.h:
typedef struct _MARGINS
{
int cxLeftWidth; // width of left border that retains its size
int cxRightWidth; // width of right border that retains its size
int cyTopHeight; // height of top border that retains its size
int cyBottomHeight; // height of bottom border that retains its size
} MARGINS, *PMARGINS;
and its documentation:
cxLeftWidth: int - Width of the left border that retains its size.
cxRightWidth: int - Width of the right border that retains its size.
cyTopHeight: int - Height of the top border that retains its size.
cyBottomHeight: int - Height of the bottom border that retains its size.
Chop and Paint
The Luna theme is telling us that when we draw ListViewHeader.bmp, we need to use the sizing margins:
SizingMargins = 8, 8, 3, 4
And cut the image up into 9 pieces (3x3). But rather than using 6px all around (like i said in my question), we need to use the sizes that the designer of the image intended:
Left: 8
Right: 8
Top: 3
Bottom: 4
So given the 18×18 theme element image created in Photoshop by a designer:
The person who created the image said that my drawing code needs to cut off:
left 8 pixels
right 8 pixels
top 3 pixels
bottom 4 pixels
Meaning i then have to draw each of the nine images:
And then stretch draw some parts in certain directions:
Top-left: draw unstretched
Left: stretch vertically
Bottom-left: draw unstretched
Top: draw stretch horizontally
Middle: draw stretched horizontally and vertically
Bottom: draw stretched horizontally
Top-right: draw unstretched
Right: draw stretched vertically
Bottom-right: draw unstretched

Layout Constraint issues with 2 side by side UILabels

I have 2 UILabels side by side. The one on the right grows as the content inside changes (using sizeToFit) and when it grows, the one on the left should shrink and truncate if needed.
Here are the current constraints I have:
The left label:
Leading space to superview: 8
Width <= 156
Top space to superview: 0
Height: 32
Trailing space to right label: 8
The right label:
Trailing space to superview: 8
Width >= 0
Top space to superview: 0
Height: 32
Leading space to left label: 8
Leading space to superview <= 172
Using what I have here the right label will grow as it should, but the left label will not shrink and truncate the text inside. What am I doing wrong?
Edit: Both labels should have a static height. The right labels width should grow and the left labels width should shrink.
For growing and shrink constraints each UIView have this methods:
contentCompressionResistancePriorityForAxis:// For setup shrink constraints
contentHuggingPriorityForAxis:// For setup growing constraints
Don't forget of priority.
p.s. Storyboards have same fields in params for each view.

Scrollview doesn't scroll in Xcode

I have a scroll view with the constraints:
equal width to Safe Area
equal height to Safe Area
Align Center X to Superview
Align Center Y to Superview
It contains only a vertical Stack View with the following constraints:
Align Center X to: SuperView
Proportional Width to Superview (multiplier 0.9)
Top Space to Superview: 0
Now, if I add enough items to the stack view, so that it exceeds the bottom of the Scrollview, I can't scroll it. Why is that so and how can I make it work?
here is my storyboard:
https://drive.google.com/file/d/1TZHl3d_HCptqx8ezcOpNJjH8RSitOln5/view?usp=sharing

Alignment of buttons in view

I have 4 buttons in an row, how can i align this in the middle on each device? iphone 4s, iphone 5s, iphone 6, iphone 6 plus.
Only on the iphone 6 it looks good. On the iphone 4s the buttons going outside the view and on the 5s and 6 plus is it not centered.
On the left view you see the layout, and the right view you see an preview.
How can i fix this issue? I have tried auto layout but this doesn't work..
Here with the constraint alignment (horizontal) on each button. But they are not in the middle..
thank you.
To align multiple buttons in the center of the canvas, you can place two "dummy" or "helper" views on each side. Then apply the following constraints:
equal width for the two dummy views.
leading space to superview = 0 for the left dummy view.
trailing space to superview = 0 for the right dummy view.
horizontal spacing = 0 for the dummy view and the button.
horizontal spacing = some fixed value for the buttons.
You can set the dummy view's height to 0.
Below is an example in the storyboard. For the sake of simplicity, I only included two buttons. You can have as many buttons as you like using this method.
I might be missing something here. But is it all that you need, to have multiple buttons centered vertically in the container and also horizontally (with no overlap and good symmetry). If so, you can do the below.
The constraints are -
Button A - Center vertically in container
Button B:Center Y = Button A:Center Y; Button C:Center Y = Button B:Center Y
Button A: Leading space to superview = some constant (say 30)
Button C: Trailing space to superview = same constant as above
Horizontal spacing (Button A - Button B) = Horizontal spacing (Button B - Button C) = some constant (say 10)
Width (Button A) = Width (Button B) = Width (Button C)

How to shift pixels of a pixmap efficient in Qt4

I have implemented a marquee text widget using Qt4. I painted the text content onto a pixmap first. And then paint a portion of this pixmap onto a paint device by calling painter.drawTiledPixmap(offsetX, offsetY, myPixmap)
My Imagination is that, Qt will fill the whole marquee text rectangle with the content from myPixmap.
Is there a ever faster way, to shift all existing content to left by 1px and than fill the newly exposed 1px wide and N-px high area with the content from myPixmap?
Well. This is a trick I used to do with slower hardware back in the old days. Basically, the image buffer is allocated twice as wide as needed with 1 extra line at the beginning. Build the image to the left of the buffer. Then draw the image repeatedly with the buffer advancing 1 pixel at a time in the buffer.
int w = 200;
int h = 100;
int rowBytes = w * sizeof(QRgb) * 2; // line buffer is twice as the width
QByteArray buffer(rowBytes * (h + 1), 0xFF); // 1 more line than the height
uchar * p = (uchar*)buffer.data() + rowBytes; // start drawing the image content at 2nd line
QImage image(p, w, h, rowBytes, QImage::Format_RGB32); // 1st line is used as the padding at the start of scroll
image.fill(qRgb(255, 0, 0)); // well. do something to the image
p = image.bits() - rowBytes / 2; // start scrolling at the middle of the 1st (blank) line
for(int i=0;i<w;++i, p+=sizeof(QRgb)) {
QImage scroll(p, w, h, rowBytes, QImage::Format_RGB32); // scrool 1 pixel at a time
scroll.save(QString("%1.png").arg(i));
}
I am not sure this will be any faster than just change the offset of the image and draw it strait. The hardware today is really powerful which renders a lot of old tricks useless. But it's fun to play obscure tricks. :)
Greetings,
one possibility to achieve this would be to:
Create a QGraphicsScene + View and put the pixmap on that twice (as QGraphicsPixmapItem), so they are right next to each other.
Size the view to fit the size of the (one) pixmap.
Then, instead of repainting the pixmap, you simply reposition the view's viewport, moving from one pixmap to the next.
Jump back at the end to create the loop.
This may or may not be faster (in terms of performance) - I have not tested it. But may be worth a try, if only for the sake of experiment.
Your approach is probably one of the fastest one since you use low level painting methods. You can implement an intermediate approach between low level painting and the QGraphicsScene option : using a scroll area containing a label.
Here is a sample of code that create a new scroll area containing a text label. You may scroll the label automatically using a QTimer to trigger the scrolling effect, that gives you a nice marquee widget.
QScrollArea *scrollArea = new QScrollArea();
// ensure that scroll bars never show
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
QLabel *label = new QLabel("your scrolling text");
// resize the scroll area : 50px length and an height equals to its content height.
scrollArea->resize(50, label->size().height());
scrollArea->setWidget(label);
label->show(); // optionnal if the scroll area is not yet visible
The text label inside the scroll area can be moved from left to right by one pixel using the QScrollArea::scrollContentsBy(int dx, int dy) with a dx parameter equals to -1.
Why not just do it on a pixel by pixel basis? Due to the way caches work writing the pixel to the one before it all the way until you get to the end. Then you can fill the final column by reading from your other image.
Its then pretty easy to SIMD optimise it as well; though you start getting into per-platform optimisations at this point.

Resources