Tiled background for UITableViewCells whose height is not known in advance - cocoa-touch

My app has a grouped table view, and the cells use linen as their background, with no divider. The linen pattern repeats perfectly when tiled 150x150, but if cell 0 is 100 pixels tall, since the pattern starts again at pixel 0 in cell 1 it becomes noticeable, as the lines in the linen wouldn't match up. The linen ends where the table view ends, and so it needs to scroll with it too.
Any ideas on how I can get this to work more gracefully?

If you're using UIColor to set your pattern background, you probably need to switch to putting in a UIImageView. Set the frame appropriately, but adjust the origin of the bounds to scroll the inner content.
So the cell at row 0 will have bounds with origin.y = 0. The cell at row n will have bounds with origin.y = (n * [your cell height])%[your source texture height]. In order to handle wraparound (eg, if your cell were meant to contain the final line of your source pattern at the top, then roll back onto the first line) you'll probably want to create a modified texture image that's [cell height] + [source texture height] - 1 pixels tall and has the first portion of the texture repeating at the bottom.

Related

iOS constraints: 4 Buttons

I would like to place 4 buttons on the screen. They should be all of the same height and width. The margin between the buttons should be 35px and the outter margin to the views border should be 20px.
Now the buttons should be scaling to the different sizes of the screen. But all my tries with the constrains have failed.
Does somebody know how to use them properly?
layout:
---------------
| |
| x x |
| |
| x x |
| |
---------------
X are the buttons
If the result you want is the one presented below, please follow the steps:
Always keep in mind this method. Design your view as-it-should-render in your storyboard (600x600) and then apply your constraints.
Position your four buttons as expected for a 600x600px. view:
Select all buttons, then choose "Equal Width" and "Equal Height" constraint in the lower Constraint helper:
Drag-n-drop from B1 to B2 with Ctrl key pressed, release and select "Horizontal Spacing". Do the same between B3 and B4.
Repeat the previous step with B1/B3 and B2/B4 but choose "Vertical Spacing".
For B1, attach-it to 20px. from left and top bounds as presented below:
Deselect Constraint to margins before applying constraint.
Do the same for B2 (top/right), B3 (left/bottom) and B4 (right/bottom).
You're all set, your view will now scale appropriately, no matter what's the screen size.
You could write a program to calculate the sizes of the buttons. First, get your screen width, say 320. Then: 320 = 20 + button width + 35 + button width + 20
2 * button width = 245. button width = 122.5.
The same would apply for the height.
I would do the following:
1) Add a 1x1 view which has a background color which is clear and add constraints which center it relative to the containing view. This gives you a point in the center.
2) For the left buttons, set the trailing distance to the 1x1 view as 17.5.
3) For the right buttons. set the leading distance to the 1x1 view as 17.5.
4) For the top buttons, set the bottom distance to the 1x1 view as 17.5.
5) For the bottom buttons, set the top distance to the 1x1 view as 17.5.
This gives you the buttons relative to this 1x1 view. You can move this up or down now if you want the buttons at the top or bottom etc... Now you want to handle the scaling of the width.
6) Add an aspect ratio for the buttons which meets your needs. 1:1 for square etc.
7) For the left buttons, set the leading distance to the containing view to be 20pts.
8) For the right buttons, set the trailing distance to the containing view to be 20pts.
As you have the aspect ratio set, the buttons should scale width and height proportionally to satisfy the 20pt constraint and constraint to the 1x1 center point.

How does PDF line width interact with the CTM in both horizontal and vertical dimensions?

I'm trying to figure out exactly how line width affects a stroked line in PDF, given the current transformation matrix (CTM). Two questions...
First: how do I convert the line width to device space using the CTM? Page 208 in the PDF 1.7 Reference, which describes how to convert points using the CTM, assumes the input data is an (x, y) point. Line width is just a single value, so how do I convert it? Do I create a "dummy" point from it like (lineWidth, lineWidth)?
Second: once I make that calculation, I'll get another (x, y) point. If the CTM has different scaling factors for horizontal vs. vertical, that gives me two different line widths. How are these line widths actually applied? Does the first one (x) get applied only when drawing horizontal lines?
A concrete example for the second question: if I draw/stroke a horizontal line from (0, 0) to (4, 4) with line width (2, 1), what are the coordinates of the bounding box of the resulting rectangle (i.e., the rectangle that contains the line width)?
This is from Page 215 in the Reference, but it doesn't actually explain how the thickness of stroked lines will vary:
The effect produced in device space depends on the current transformation matrix
(CTM) in effect at the time the path is stroked. If the CTM specifies scaling by
different factors in the horizontal and vertical dimensions, the thickness of
stroked lines in device space will vary according to their orientation.
how do I convert the line width to device space using the CTM?
The line width essentially is the line size perpendicular to its direction. Thus, to calculate the width after transformation using the CTM, you choose a planar vector perpendicular to the original line whose length is the line width from the current graphics state, apply the CTM (without translation, i.e. setting e and f to 0) to that vector (embedded in the three dimensional space by setting the third coordinate to 1) and calculate the length of the resulting 2D vector (projecting on the first two coordinates).
E.g. you have a line from (0,0) to (1,4) in current user space coordinates with a width of 1. You have to find a vector perpendicular to it, e.g. (-4,1) by rotating 90° counter clockwise, and scale it to a length of 1, i.e. ( -4/sqrt(17), 1/sqrt(17) ) in that case.
If the CTM is the one from #Tikitu's answer
CTM has a horizontal scaling factor of 2 and a vertical scaling factor of 1
it would be
2 0 0
0 1 0
0 0 1
This matrix would make the line from the example above go from (0,0) to (2,4) and the "width vector" ( -4/sqrt(17), 1/sqrt(17) ) would be transformed to ( -8/sqrt(17), 1/sqrt(17) ) (the CTM already has no translation part) with a length of sqrt(65/17) which is about 1.955. I.e. the width of the resulting line (its size perpendicular to its direction) is nearly 2.
If the original line would instead have been (0,0) to (4,1) with width 1, a width vector choice would have been ( -1/sqrt(17), 4/sqrt(17) ). In that case the transformed line would go from (0,0) to (8,1) and the width vector would be transformed to ( -2/sqrt(17), 4/sqrt(17) ) with a length of sqrt(20/17) which is about 1.085. I.e. the width of the resulting line (perpendicular to its direction) is slightly more than 1.
You seem to be interested in the "corners" of the line. For this you have to take start and end of the transformed line and add or subtract half the transformed width vector. In the samples above:
(original line from (0,0) to (1,4)): ( -4/sqrt(17), 1/(2*sqrt(17)) ), ( 4/sqrt(17), -1/(2*sqrt(17)) ), ( 2-4/sqrt(17), 4+1/(2*sqrt(17)) ), ( 2+4/sqrt(17), 4-1/(2*sqrt(17)) );
(original line from (0,0) to (4,1)): ( -1/sqrt(17), 2/sqrt(17) ), ( 1/sqrt(17), -2/sqrt(17) ), ( 8-1/sqrt(17), 1+2/sqrt(17) ), ( 8+1/sqrt(17), 1-2/sqrt(17) ).
Don't forget, though, that PDF lines often are not cut off at the end but instead have some cap. And furthermore remember the special meaning of line width 0.
I don't know anything about PDF internals, but I can make a guess at what that passage might mean, based on knowing a bit about using matrices to represent linear transformations.
If you imagine your stroked line as a rectangle (long and thin, but with a definite width) and apply the CTM to the four corner points, you'll see how the orientation of the line changes its width when the CTM has different horizontal and vertical scaling factors.
If your CTM has a horizontal scaling factor of 2 and a vertical scaling factor of 1, think about lines at various angles:
a horizontal line (a short-but-wide rectangle) gets its length doubled, and it's "height" (the width of the line) stays the same;
a vertical line (a tall-and-thin rectangle) gets it's width doubled (i.e., the line gets twice as thick), and it's length stays the same;
lines at various angles get thicker by different degrees, depending on the angle, because they get stretched horizontally but not verticallye.g.
the thickness of a line at 45 degrees is measured diagonally (45 degrees the other way), so it gets somewhat thicker (some horizontal stretching), but not twice as thick (the vertical component of the diagonal didn't get bigger). (You can figure out the thickness with two applications of the Pythagorean theorem; it's about 1.58 times greater, or sqrt(5)/sqrt(2).)
If this story is correct, you can't convert line width using the CTM: it is simply different case-by-case, depending on the orientation of the line. What you can convert is the width of a particular line, with a particular orientation, via the trick of thinking of the line as a solid area and running its corners individually through the CTM. (This also means that "the same" line, with the same thickness, will look different as you vary its orientation, if your CTM has different horizontal and vertical scaling factors.)

How to change the anchor point from the top-left corner of a transformation matrix to the bottom-left corner?

Say, I have an image on an HTML page.
I apply an affine transformation to the image using CSS3 matrix function.
It looks like:
img#myimage {
transform: matrix(a, b, c, d, tx, ty);
/* use -webkit-transform, -moz-transform etc. */
}
The origin of an HTML page is the top-left corner and the y-axis is inverted.
I'm trying to put the same image in an environment (cocos2d) where the origin is the bottom-left corner and the y-axis is upright.
To get the same result in the other environment, I need to transform the origin somehow and reflect that in the resulting CGAffineTransform.
It would be great if I can get some help with the matrix math that goes here. (I'm not so good with matrices.)
The following formula would work,
for converting the position from CSS3 to Cocos2d:
(screen Size - "y" position in CSS3 - height of object)
Explanation:
To make the origin for the Cocos environment same as for the CSS3 environment we would only have to add the screen size to the cocos2d's bodies y co-ordinate.
Eg. The screen size is (100,100) and the body is a point object if you place it at (0,0) in CSS3 it would be at the top left corner. If we add the screen size to the y co-ordinates for cocos2d the object would be placed at (0,100) which is the top-left corner for cocos2d as well
To make the co-ordinates same, since the Y axis is inverted, we have to subtract the "Y" co-ordinate given in CSS3 from the Screen Size for Cocos2d. Suppose we place the same point object in the previous example at (0,10) in CSS3 we would place it at (0, 100 - 10) in cocos2d which would be the same positions on the screen
Since our body would NOT always be a point object we have to take care of its anchor point as well. If suppose the body's height is 20 and we place it at (0,10) in CSS3 then it would be placed at the top-left position and would be coming down because the Y axis is inverted
Hence we would also have to subtract the body's total height from the screen size and "y" co-ordinate to place it at the same position which would be (0, 100 - 10 - 20) putting the body at the same place in cocos2d environment
I hope I am correct and clear :)

Visualizing the Anchor Point of a UIImageView

Is there an easy way of putting a mark (like a cross for example) on the anchor point of an UIImageView? I'm trying to line up several rotating images by their anchor point, and being able to see these points would make the job a lot easier.
Many thanks.
You are asking how to visualize the anchor point within a view but it seem to me that you are asking for it so that you can help align the anchor points. I'll try and answer both questions.
Visualizing the anchor point.
Every view on iOS have an underlying layer that has an anchor point. The anchor point is in unit coordinate space of the layer (x and y goes from 0 to 1). This means that you can multiply x by the width and y by the height to get the position of the anchor point inside the layer in the coordinate space of the view/layer. You can then place a subview/sublayer there to show the location of the anchor point.
In code you could do something like this to display a small black dot where the anchor point is.
CALayer *anchorPointLayer = [CALayer layer];
anchorPointLayer.backgroundColor = [UIColor blackColor].CGColor;
anchorPointLayer.bounds = CGRectMake(0, 0, 6, 6);
anchorPointLayer.cornerRadius = 3;
CGPoint anchor = viewWithVisibleAnchorPoint.layer.anchorPoint;
CGSize size = viewWithVisibleAnchorPoint.layer.bounds.size;
anchorPointLayer.position = CGPointMake(anchor.x * size.width,
anchor.y * size.height);
[viewWithVisibleAnchorPoint.layer addSublayer:anchorPointLayer];
You can see the result in the image below for four different rotations.
Aligning layers by their anchor point
That is cool and all but it's actually easier then that to align anchor points.
The key trick is that the position and the anchorPoint is always the same point, only in two different coordinate spaces. The position is specified in the coordinate space of the super layer. The anchor point is specified in the unit coordinate space of the layer.
The nice thing about this is that views that have their position property aligned will automatically have their anchorPoint aligned. Note that the content is drawn relative to the anchor point. Below is an example of a bunch of views that all have the same y component of their position, thus they are aligned in y.
There really isn't any special code to do this. Just make sure that the position properties are aligned.

Position Subviews Relative to Screen Estate

I'd like to display multiple small UIViews as Subviews relative to the screen estate. This should work across different screen sizes (iPad, iPhone)/portrait/landscape modes.
Each subview to display has two NSNumber objects with an unsigned int ranging from -100 (min) to 100 (max) which needs to be mapped to the correct x and y coordinates for positioning.
What's the best way to translate those values (-100...100) to use them for positioning UIViews on the screen?
How do I position them in a relative rather then an absolute way, so that the code works across screen rotation and screen sizes?
Ok, so if I understand correctly you want a -100 in the x direction to map to the left most point on the screen, 100 in the x to map to the right most point on the screen, -100 in the y direction to map to the lowest point on the screen, and 100 in the y to map to the highest point on screen (or maybe you want the y inverted from what I have so that it agrees with the screen coordinate system in which y becomes bigger the lower on the screen you get?).
And we also want to account for rotation.
As far as I understand it, asking UIScreen for its height and width:
CGFloat width = [UIScreen mainScreen].bounds.size.width;
CGFloat height = [UIScreen mainScreen].bounds.size.height;
but this does not account for rotation. The only other way I am aware of that is pretty straightforward would be to ask a UIView covering the screen for its width and height (most simply, you could make your viewcontroller's view cover the whole screen).
If you had a UIView that perfectly covered the whole screen (let's call it myView), you could try:
CGFloat width = myView.frame.size.width;
CGFloat height = myView.frame.size.height;
these should adjust for orientation by themselves (from my experience, it should definitely work if you get the height and width in viewDidAppear:animated: or anything after. also the UIView needs to either be the UIViewControllers view property or a subview of this view. if not, you'll have to implement didRotateFromInterfaceOrientation: or find some other way to tell your view about any rotations). Once we have the 'width' and 'height' of the screen, we can convert from your int's to screen position. Try something like:
(CGPoint)convertX:(NSNumber *)x andY:(NSNumber *)y intoPoint
{
pointX = ([x intValue] + 100.0)*width/200.0;
pointY = (-[y intValue] + 100.0)*height/200.0; // remove the - sign at the front of the expression for y to grow as you move down the screen
return CGPointMake(pointX, pointY);
}
to convert from -100 to 100 in x and y to their respective points on the screen.
If you're working with a range of +/-100, then you may want to use the underlying CALayers to position your views. The nice part about CALayers, is that their anchor points are mapped to a device-agnostic grid that ranges from 0.0 to +1.0 on a Cartesian plane.