-(IBAction)bigger {
must.bounds.size = CGSizeMake(must.bounds.size.width +5.0 , must.bounds.size.height +5.0);
}
This is the code I input but I get the error saying that the expression is not assignable. Must is a uiimageview. I want to make each property (height and width) bigger by 5.0 each time i press the button. How can i do this.
What you probably want is to set the frame instead of the bounds. Do something like:
CGRect frame = must.frame;
frame.size.width += 5;
frame.size.height += 5;
must.frame = frame;
//here u can get the image as bigger without moving its center point
-(IBAction)bigger {
CGRect _bounds = must.bounds;
CGPoint centerPoint=must.center;
_bounds.size = CGSizeMake(must.bounds.size.width + 5.0 , must.bounds.size.height + 5.0);
must.bounds = _bounds;
must.center = centerPoint;
}
Related
This has been driving me crazy.. I have a large image, and need to have a view that is both zoomable, and scrollable (ideally it should also be able to rotate, but I've given up on that part). Since the image is very large, I plan on using CATiledLayer, but I simply can't get it to work.
My requirements are:
I need to be able to zoom (on mouse center) and pan
The image should not change its width:height ratio (shouldn't resize, only zoom).
This should run on Mac OS 10.9 (NOT iOS!)
Memory use shouldn't be huge (although up to like 100 MB should be ok).
I have the necessary image both complete in one file, and also tiled into many (even have it for different zoom levels). I prefer using the tiles, as that should be easier on memory, but both options are available.
Most of the examples online refer to iOS, and thus use UIScrollView for the zoom/pan, but I can't get to copy that behaviour for NSScrollView. The only example for Mac OS X I found is this, but his zoom always goes to the lower left corner, not the middle, and when I adapt the code to use png files instead of pdf, the memory use gets around 400 MB...
This is my best try so far:
#implementation MyView{
CATiledLayer *tiledLayer;
}
-(void)awakeFromNib{
NSLog(#"Es geht los");
tiledLayer = [CATiledLayer layer];
// set up this view & its layer
self.wantsLayer = YES;
self.layer = [CALayer layer];
self.layer.masksToBounds = YES;
self.layer.backgroundColor = CGColorGetConstantColor(kCGColorWhite);
// set up the tiled layer
tiledLayer.delegate = self;
tiledLayer.levelsOfDetail = 4;
tiledLayer.levelsOfDetailBias = 5;
tiledLayer.anchorPoint = CGPointZero;
tiledLayer.bounds = CGRectMake(0.0f, 0.0f, 41*256, 22*256);
tiledLayer.autoresizingMask = kCALayerNotSizable;
tiledLayer.tileSize = CGSizeMake(256, 256);
self.frame = CGRectMake(0.0f, 0.0f, 41*256, 22*256);
self.layer = tiledLayer;
//[self.layer addSublayer:tiledLayer];
[tiledLayer setNeedsDisplay];
}
-(void)drawRect:(NSRect)dirtyRect{
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
CGFloat scale = CGContextGetCTM(context).a;
CGSize tileSize = tiledLayer.tileSize;
tileSize.width /= scale;
tileSize.height /= scale;
// calculate the rows and columns of tiles that intersect the rect we have been asked to draw
int firstCol = floorf(CGRectGetMinX(dirtyRect) / tileSize.width);
int lastCol = floorf((CGRectGetMaxX(dirtyRect)-1) / tileSize.width);
int firstRow = floorf(CGRectGetMinY(dirtyRect) / tileSize.height);
int lastRow = floorf((CGRectGetMaxY(dirtyRect)-1) / tileSize.height);
for (int row = firstRow; row <= lastRow; row++) {
for (int col = firstCol; col <= lastCol; col++) {
NSImage *tile = [self tileForScale:scale row:row col:col];
CGRect tileRect = CGRectMake(tileSize.width * col, tileSize.height * row,
tileSize.width, tileSize.height);
// if the tile would stick outside of our bounds, we need to truncate it so as
// to avoid stretching out the partial tiles at the right and bottom edges
tileRect = CGRectIntersection(self.bounds, tileRect);
[tile drawInRect:tileRect];
}
}
}
-(BOOL)isFlipped{
return YES;
}
But this deforms the image, and doesn't zoom or pan correctly (but at least the tile selection works)...
I can't believe this is so hard, any help would be greatly appreciated. Thanks :)
After a lot of research and tries, I finally managed to get this to work using this example. Decided to post it for future reference. Open the ZIP > CoreAnimationLayers> TiledLayers, there's a good example there. That's how CATiledLayer works with OS X, and since the example there doesn't handle zoom very well, I leave here my zoom code
-(void)magnifyWithEvent:(NSEvent *)event{
[super magnifyWithEvent:event];
if (!isZooming) {
isZooming = YES;
BOOL zoomOut = (event.magnification > 0) ? NO : YES;
if (zoomOut) {
[self zoomOutFromPoint:event.locationInWindow];
} else {
[self zoomInFromPoint:event.locationInWindow];;
}
}
}
-(void)zoomInFromPoint:(CGPoint)mouseLocationInWindow{
if(zoomLevel < pow(2, tiledLayer.levelsOfDetailBias)) {
zoomLevel *= 2.0f;
tiledLayer.transform = CATransform3DMakeScale(zoomLevel, zoomLevel, 1.0f);
tiledLayer.position = CGPointMake((tiledLayer.position.x*2) - mouseLocationInWindow.x, (tiledLayer.position.y*2) - mouseLocationInWindow.y);
}
}
-(void)zoomOutFromPoint:(CGPoint)mouseLocationInWindow{
NSInteger power = tiledLayer.levelsOfDetail - tiledLayer.levelsOfDetailBias;
if(zoomLevel > pow(2, -power)) {
zoomLevel *= 0.5f;
tiledLayer.transform = CATransform3DMakeScale(zoomLevel, zoomLevel, 1.0f);
tiledLayer.position = CGPointMake((tiledLayer.position.x + mouseLocationInWindow.x)/2, (tiledLayer.position.y + mouseLocationInWindow.y)/2);
}
}
I have an issue with scroll view. I have implemnted two font resize buttons to increase or decrease text font size for the text view embedded in the scroll view. But after decreasing font size, I calculate the scroll view content and reize it to adapt to the new text view height. But every time I modify text font, it scrolls down for every step.
Here is the code:
- (IBAction)decreaseText:(id)sender {
int MyTextSizeMin = 8;
int MyTextSizeMax = 20;
// disable buttons when they're out of the range.
BOOL smallerEnabled = textFontSize > MyTextSizeMin;
BOOL biggerEnabled = textFontSize < MyTextSizeMax;
[self.decreaseText setEnabled:smallerEnabled];
[self.increaseText setEnabled:biggerEnabled];
height =0;
CGFloat secondLabelsize = texto.font.pointSize;
[texto setFont:[UIFont systemFontOfSize:(secondLabelsize-1)]];
CGRect frame = texto.frame;
frame.size.height = texto.contentSize.height;
self.texto.frame = frame;
height +=texto.contentSize.height;
height += self.imagen.image.size.height;
height += self.fecha.frame.size.height;
height += self.titulo.frame.size.height;
height += 200;
self.scrollView.contentSize=CGSizeMake(300.0,height);
[self.scrollView setNeedsDisplay];
}
How can I disable this undesired scroll?
Many thanks!
Try it may it help full for you.
[scrollView scrollRectToVisible:CGRect animated:BOOL];
I would like to know the width of the dark grey frame on either side of the inside picker part and the width of the separators between components. This would be at default settings (eg. what's shown in the .xib). Or, how to find such values programmatically. Thank you
To clarify, I'm looking for what the "suggested minimums" might be for those values. I'm putting my UIPickerView in a popover, and the UIPickerView is wider than 320 px (which is what the .xib gives as the "default"). I would like to know these values so I can add them to the popover's width to make sure it doesn't cut off components on the right side of the UIPickerView.
Well this can be a little tricky since the Picker can have a dynamic number of components. So in order to find the widths you have to take into account the number of components. This can be done like so:
NSInteger n = picker.numberOfComponents;
const CGFloat separatorWidth = 8.0f;
const CGFloat sectionExceedWidth = -2.0f;
CGFloat totalWidth = picker.bounds.size.width;
CGFloat panesWidth = totalWidth - separatorWidth * (n - 1);
for (NSInteger i = 0; i < n; i++) {
CGFloat sectionWidth = [picker rowSizeForComponent:i].width + sectionExceedWidth;
panesWidth -= sectionWidth;
}
CGFloat leftPaneWidth = ceilf(panesWidth * 0.5f);
CGFloat rightPaneWidth = panesWidth - leftPaneWidth;
CGFloat totalHeight = picker.bounds.size.height;
CGRect totalRect = CGRectMake(0, 0, totalWidth, totalHeight);
Where the left and right panes widths are found and the separator size is static.
This was pulled from here.
I'm trying to zoom the drawing on the context based on pinching in and out. This is working perfectly, but it will always zoom from the origin (top left). This doesn't give the nice effect you get in other applications and is really annoying. The old zooming method is as follows:
- (IBAction)handlePinchGesture:(UIGestureRecognizer *)sender {
UIPinchGestureRecognizer *pinch = (UIPinchGestureRecognizer *)sender;
if ([pinch scale] > zoomLevel + MAX_ZOOM_PER_CALL) {
[pinch setScale: zoomLevel + MAX_ZOOM_PER_CALL];
}
if ([pinch scale] < zoomLevel - MAX_ZOOM_PER_CALL) {
[pinch setScale:zoomLevel - MAX_ZOOM_PER_CALL];
}
float prevZoomLevel = zoomLevel;
CGFloat factor = [pinch scale];
zoomLevel = factor;
if (zoomLevel < MIN_ZOOM_LEVEL) {
zoomLevel = MIN_ZOOM_LEVEL;
}
if (zoomLevel > MAX_ZOOM_LEVEL) {
zoomLevel = MAX_ZOOM_LEVEL;
}
//The next piece of code is added here
[self setNeedsDisplay];
}
The actual zooming is done in the drawing methods of the parts that are shown on the context. I was thinking of changing the origin of the screen (that is the relative origin to the items that are to be drawn) so it would simulate this. But it is not working at all, this is what i have right now:
float dZoomLevel = zoomLevel - prevZoomLevel;
if (dZoomLevel != 0) {
CGPoint touchLocation = [pinch locationInView:self];
CGPoint zoomedTouchLocation = CGPointMake(touchLocation.x * prevZoomLevel, touchLocation.y * prevZoomLevel);
CGPoint newLocation = CGPointMake(touchLocation.x * zoomLevel, touchLocation.y * zoomLevel);
float dX = ( newLocation.x - zoomedTouchLocation.x );
float dY = ( newLocation.y - zoomedTouchLocation.y );
_originX += roundf(dX);
_originY += roundf(dY);
}
The origin is taken from the xml (the smallest x and y of all the elements). It will usually be something between 12000 and 20000 but could in theory be between 0 and 100000.
I'm not sure if I've made myself clear, but if you need any information or don't understand something just ask me and i'll try to reply ASAP. Thanks in advance!
I found the answer myself. The way one needs to zoom in my case is by zooming from the point of the touch. So when the x and y coordinates get zoomed do this:
x -= pinchLocation.x;
y -= pinchLocation.y;
x *= zoomLevel;
y *= zoomLevel;
x += pinchLocation.x;
y += pinchLocation.y;
or in short:
x = (x - pinchLocation.x) * zoomLocation + pinchLocation.x;
y = (y - pinchLocation.y) * zoomLocation + pinchLocation.y;
now x and y are on the correct location!!
I am newbie so my question can be really obvious, but I didn't find any solution so far.
I did in IB UIScrollView and connected it with File's Owner.
I would like to set now the frame size of my UIScrollView (named ScrollView).
const CGFloat BoardWidth = 320;
const CGFloat BoardHeight = 400;
//I tried this way but 'Expression is assignable' - said Xcode
ScrollView.frame.size.width = BoardWidth;
ScrollView.frame.size.height = BoardWidth;
So how can I the easiest set own sizes of ScrollView frame?
CGRect scrollFrame = CGRrectMake(x, y, w, h);
ScrollView.frame = scrollFrame;
Or if you need only to change the width and height;
CGRect scrollFrame;
scrollFrame.origin = ScrollView.frame.origin;
scrollFrame.size = CGSizeMake(w, h);
ScrollView.frame = scrollFrame;
Edit keeping the center unchanged:
CGRect scrollFrame;
CGFloat newX = scrollView.frame.origin.x + (scrollView.frame.size.width - w) / 2;
CGFloat newY = scrollView.frame.origin.y + (scrollView.frame.size.height - y) / 2;
scrollFrame.origin = CGPointMake(newX, newY);
scrollFrame.size = CGSizeMake(w, h);
scrollView.frame = scrollFrame;
you need to do this, for example.
ScrollView.frame = CGRectMake(0, 0, BoardWidth, BoardHeight);
Once done you need also to set contentSize property. It's the area that 'extends' behind the frame of your UIScrollView.
If you want to scroll only horizontally:
ScrollView.contentSize = CGSizeMake(w * BoardWidth, BoardHeight);
If you want to scroll only vertically:
ScrollView.contentSize = CGSizeMake(BoardWidth, h * BoardHeight);
If you want to scroll both horizontally and vertically:
ScrollView.contentSize = CGSizeMake(w * BoardWidth, h * BoardHeight);
where w and h are generic values to increment your width and/or your height.
If you want have an horizontal (for example) discrete scroll (e.g. you have some pages with the same dimension of your screen).
ScrollView.pagingEnabled = YES;
ScrollView.contentSize = CGSizeMake(p * BoardWidth, BoardHeight);
where p is the number of pages you want to display.
Hope it helps.
You can do it as below,
scrollView.frame = CGRectMake(xOrigin,yOrigin,width,height);
If you are looking for content size of scrollview then it as below,
scrollView.contentSize = CGSizeMake(width,height);
CGRect Frame = ScrollView.frame
Frame.frame.size.width = BoardWidth;
Frame.frame.size.width = BoardWidth;
ScrollView.frame = Frame;
Since frame is a structure..you can't set the frame of an object directly.. You will have to make a Cgrect and then manipulate it.
using contentSize property
ScrollView.contentSize = CGSizeMake(320, 520);
it needs to be bigger than the frame so it actually scrolls.