__block modifier creates unreadable memory - ios

Now Im developing a banner showing feature in iOS
It's a singleton which shows banner on the upper part of screen when user logs in.
It's basically a shared view with a class method showWithName...
#interface XXUserWelcomeBanner ()
{
UIImageView *logoView;
UILabel *textLabel;
CGFloat _width;
}
#end
When user calls, it creates a UIImageView and a UILabel to add on self. And animates itself onto the screen.
+ (XXUserWelcomeBanner *)shared {
static dispatch_once_t onceToken;
static XXUserWelcomeBanner *userWelcomBanner;
dispatch_once(&onceToken, ^{
userWelcomBanner = [[XXUserWelcomeBanner alloc] init];
});
return userWelcomBanner;
}
+ (void)showWithUserName:(NSString *)userID andLogo:(UIImage * _Nullable)logo {
dispatch_async(dispatch_get_main_queue(), ^{
[[self shared] createWithName:userID andLogo:logo];
});
}
So there's this other bug I just found that causes this method to be called twice and on the second time it shows only the UIImageView.
And I don't understand why that's happening.
Because the UIImageView and UILabel won't be created twice.
Here's more code.
#pragma mark - private
- (void)createWithName:(NSString *)name andLogo:(UIImage * _Nullable)logo {
self.opaque = NO;
self.alpha = 0.9;
self.backgroundColor = COLOR(0xfcfcfc);
// if (#available(iOS 13.0, *)) {
// self.backgroundColor = UIColor.secondarySystemBackgroundColor;
// }
CGSize labelSize = CGSizeZero;
if (logoView == nil) {
if (logo != nil) {
logoView = [[UIImageView alloc] initWithImage:logo];
[self addSubview:logoView];
} else {
NSString *imagePath = [XXUtility pathForResourceNamed:#"Logo" withExtension:#"png"];
UIImage *imageToAdd = [[UIImage alloc] initWithContentsOfFile:imagePath];
logoView = [[UIImageView alloc] initWithImage:imageToAdd];
[self addSubview:logoView];
}
}
if (textLabel == nil) {
textLabel = [[UILabel alloc] init];
NSString * labelString = [NSString stringWithFormat:NSLocalizedStringWithDefaultValue(#"welcom banner", #"userInterface", [XXUtility bundleForStrings], #"Dear %#, welcome into game", #"user welcome banner text"), name];
labelSize = [labelString sizeWithAttributes:#{NSFontAttributeName : textLabel.font}];
textLabel.text = labelString;
[self addSubview:textLabel];
}
NSLog(#"XXUserWelcomeBanner Label size is %f x %f", labelSize.height, labelSize.width);
[self bannerSizeWithLabelSize:labelSize];
CGFloat bannerHeight = self.frame.size.height;
CGFloat bannerWidth = self.frame.size.width;
CGFloat logoHeight = bannerHeight * 0.45;
CGFloat logoWidth = logoHeight;
CGFloat logoXPos = (bannerWidth - logoWidth - labelSize.width) / 2;
CGFloat logoYPos = (bannerHeight - logoHeight) / 2;
CGFloat labelHeight = labelSize.height;
CGFloat labelWidth = labelSize.width;
CGFloat labelXPos = logoXPos + logoWidth + 5;
CGFloat labelYPos = (bannerHeight - labelHeight) / 2;
logoView.frame = CGRectMake(logoXPos, logoYPos, logoWidth, logoHeight);
textLabel.frame = CGRectMake(labelXPos, labelYPos, labelWidth, labelHeight);
[self bannerShow];
}
- (void)bannerSizeWithLabelSize:(CGSize)lSize {
_width = 40 + lSize.width + 5;
CGFloat height = 40;
CGFloat xPosition = ScreenWidth * 1/2 - _width * 1/2;
CGFloat yPosition = - height;
self.frame = CGRectMake(xPosition, yPosition, _width, height);
}
- (void)bannerShow {
UIViewController *vc;
if ([TOP_VIEWCONTROLLER respondsToSelector:#selector(topViewController)]) {
vc = [TOP_VIEWCONTROLLER topViewController];
} else {
vc = TOP_VIEWCONTROLLER;
}
[vc.view addSubview:self];
[UIView animateWithDuration:0.6 delay:0.2 options:UIViewAnimationOptionCurveEaseOut animations:^{
CGFloat height = 40;
CGFloat xPos = ScreenWidth * 1/2 - self->_width * 1/2;
CGFloat yPos = height * 1/3 + KiPhoneXSafeAreaDValue;
self.frame = CGRectMake(xPos, yPos, self->_width, height);
} completion:^(BOOL finished) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.6 delay:0.2 options:UIViewAnimationOptionCurveEaseIn animations:^{
CGFloat height = 40;
CGFloat xPosition = ScreenWidth * 1/2 - self->_width * 1/2;
CGFloat yPosition = - height;
self.frame = CGRectMake(xPosition, yPosition, self->_width, height);
} completion:^(BOOL finished) {
[self bannerDestroy];
self.alpha = 0;
}];
});
}];
}
- (void)bannerDestroy {
[logoView removeFromSuperview];
[textLabel removeFromSuperview];
logoView = nil;
textLabel = nil;
[self removeFromSuperview];
}
- (void)dealloc
{
//
NSLog(#"uiview dealloc");
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
#end
Thanks in advance.

It is expected that createWithName:andLogo: is calling more than once in your app. I guess you call it with different arguments, that's why it should not be inside dispatch_once(&onceToken, ^{ });. But you can optimise XXUserWelcomeBanner's init:
- (instancetype)init {
self = [super init];
if (self) {
logoView = [[UIImageView alloc] init];
[self addSubview:logoView];
textLabel = [[UILabel alloc] init];
[self addSubview:textLabel];
}
return self;
}
In createWithName:andLogo: you will have the following:
if (logo != nil) {
logoView.image = logo;
} else {
NSString *imagePath = [XXUtility pathForResourceNamed:#"Logo" withExtension:#"png"];
UIImage *imageToAdd = [[UIImage alloc] initWithContentsOfFile:imagePath];
logoView.image = imageToAdd;
}
NSString * labelString = [NSString stringWithFormat:NSLocalizedStringWithDefaultValue(#"welcom banner", #"userInterface", [XXUtility bundleForStrings], #"Dear %#, welcome into game", #"user welcome banner text"), name];
CGSize labelSize = [labelString sizeWithAttributes:#{NSFontAttributeName : textLabel.font}];
textLabel.text = labelString;

Related

iOS UITextView putting character onto next line

In this picture with a UITextView saying "Coordinate Geometry", the "e" gets put onto the next line. There is no line space there. I have also tried this with a UILabel (I switched to UITextView to try and fix the problem but there was no difference).
Here is my code for my subclass of UITextView
- (instancetype)initWithFrame:(CGRect)frame text:(NSString *)text circular:(BOOL)isCircular {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor lightGrayColor];//[UIColor clearColor];
self.alpha = 0.5;
self.textColor = [Styles mainTextColour];
[self setFont:[Styles heading2Font]];
[self setTextAlignment:NSTextAlignmentCenter];
self.text = text;
self.editable = NO;
self.contentInset = UIEdgeInsetsMake(-8, 0, -8, 0);
[self resizeFontToFix];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
NSAssert(NO, #"Don't use BubbleText -initWithFrame:, use -initWithFrame: andText: instead");
return nil;
}
- (void)resizeFontToFix {
//Resize to fix
CGFloat fontSize = self.font.pointSize;
CGFloat minSize = 6.0 * [Styles sizeModifier];
while (fontSize > minSize && [self sizeThatFits:(CGSizeMake(self.frame.size.width, FLT_MAX))].height >= self.frame.size.height) {
fontSize -= 1.0;
self.font = [self.font fontWithSize:fontSize];
}
//this below resizes to fit and centres the resulting view
// [self resizeFrameAndCentre];
}
- (void)resizeFrameAndCentre {
CGRect originalFrame = self.frame;
[self sizeToFit];
CGPoint centre = self.center;
centre.x = originalFrame.origin.x + (originalFrame.size.width / 2);
centre.y = originalFrame.origin.y + (originalFrame.size.height / 2);
self.center = centre;
}

Zooming UIImageView in a UIScrollView acts weirdly

I have the following problem, guys. I have an app that is pretty much like Apple's PhotoScroller. I want to jump from image to image by swiping the screen. I can do that, but I can't zoom the images. Here's the problem - I have an array with images. If the array has only one object inside, there's no problem with zooming. But if there are more images in the array, they acts weirdly when I try to zoom. The image is not being zoomed and it goes where it wants off the screen. Here is my code:
int pageWidth = 1024;
int pageHeight = 768;
int counter = 0;
self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, pageWidth, pageHeight)];
CGRect containerFrame = self.view.frame;
scrollView = [[UIScrollView alloc] initWithFrame:containerFrame];
[self.view addSubview:scrollView];
NSMutableArray *all = [[NSMutableArray alloc] init];
[all addObject:[UIImage imageNamed:#"222.jpg"]];
CGSize scrollSize = CGSizeMake(pageWidth * [all count], pageHeight);
[scrollView setContentSize:scrollSize];
for (UIImage *image in all)
{
UIImage *pageImage = [[UIImage alloc] init];
pageImage = [all objectAtIndex:counter];
CGRect scrollFrame = CGRectMake(pageWidth * counter, 0, pageWidth, pageHeight);
miniScrollView = [[UIScrollView alloc] initWithFrame:scrollFrame];
[scrollView addSubview:miniScrollView];
CGSize miniScrollSize = CGSizeMake(pageImage.size.width, pageImage.size.height);
[miniScrollView setContentSize:miniScrollSize];
UIImageView *tempImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, pageImage.size.width, pageImage.size.height)];
tempImageView.image = [all objectAtIndex:counter];
self.imageView = tempImageView;
miniScrollView.maximumZoomScale = 3.0;
miniScrollView.minimumZoomScale = 1.0;
miniScrollView.clipsToBounds = YES;
miniScrollView.delegate = self;
miniScrollView.showsHorizontalScrollIndicator = NO;
miniScrollView.showsVerticalScrollIndicator = NO;
miniScrollView.bouncesZoom = YES;
[miniScrollView addSubview:imageView];
counter ++;
}
[scrollView setPagingEnabled:YES];
[scrollView setScrollEnabled:YES];
}
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return imageView;
}
Do you have any ideas what's wrong? Because I am trying to get this work almost 2 weeks.
I also worked on such sort of App. The first thing that you can do is to take a separate subclass of your ScrollView so that all the paging and zooming operations can be handled easily. In your scrollView Class, You can take reference from the following code snippet.
#interface PhotoScrollView : UIScrollView<UIScrollViewDelegate,UIGestureRecognizerDelegate>
{
int finalPhotoWidth;
int finalPhotoHeight;
}
// to contain image
#property (strong, nonatomic) UIImageView *imageView;
- (id)initWithFrame:(CGRect)frame andImage:(UIImage *)photo
{
self = [super initWithFrame:frame];
if (self)
{
// Initialization code
[self initializeScrollViewWithImage:photo];
//setting gesture recognizer for single tap
UITapGestureRecognizer *singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(scrollViewSingleTapped:)];
singleTapRecognizer.delegate = self;
singleTapRecognizer.numberOfTapsRequired = 1;
[self addGestureRecognizer:singleTapRecognizer];
//setting gesture recognizer for Double tap
UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(scrollViewDoubleTapped:)];
doubleTapRecognizer.delegate = self;
doubleTapRecognizer.numberOfTapsRequired = 2;
[self addGestureRecognizer:doubleTapRecognizer];
[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];
singleTapActivated = FALSE;
self.backgroundColor = [UIColor blackColor];
self.minimumZoomScale = 1.0f;
self.maximumZoomScale = 15.0f;
self.zoomScale = 1.0f;
self.delegate = self;
}
return self;
}
//for sizing the frame by giving height and width
-(void)initializeScrollViewWithImage:(UIImage*)photo
{
finalPhotoWidth = photo.size.width;
finalPhotoHeight = photo.size.height;
//Pre-checking of frame and setting the height and width accordingly
if (finalPhotoHeight > self.frame.size.height)
{
// if photo height is bigger than frame height, re-adjust the photo height and width accordingly
finalPhotoHeight = self.frame.size.height;
finalPhotoWidth = (photo.size.width/photo.size.height) * finalPhotoHeight;
}
if (finalPhotoWidth > self.frame.size.width)
{
// if photo width is bigger than frame width, re-adjust the photo height and width accordingly
finalPhotoWidth = self.frame.size.width;
finalPhotoHeight = (photo.size.height/photo.size.width) * finalPhotoWidth;
}
if (finalPhotoHeight < self.frame.size.height && finalPhotoWidth < self.frame.size.width)
{
// if the photo is smaller than frame, increase the photo width and height accordingly
finalPhotoWidth = self.frame.size.width;
finalPhotoHeight = self.frame.size.height;
}
//initialising imageView with the thumbnail photo
self.imageView = [[UIImageView alloc] initWithImage:photo];
self.imageView.contentMode = UIViewContentModeScaleAspectFit;
//setting frame according to the modified width and height
if(!isnan(finalPhotoWidth) && !isnan(finalPhotoHeight))
{
self.imageView.frame = CGRectMake( (self.frame.size.width - finalPhotoWidth) / 2, (self.frame.size.height - finalPhotoHeight)/2, finalPhotoWidth, finalPhotoHeight);
}
// setting scrollView properties
self.contentSize = self.imageView.frame.size;
// add image view to scroll view
[self addSubview:self.imageView];
}
//to deny the simultaneous working of single and double taps
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return NO;
}
// Gesture handleer for single tap gesture
-(void)scrollViewSingleTapped:(UITapGestureRecognizer *)recognizer
{
if(!singleTapActivated)
{
//do as per requirement
singleTapActivated = TRUE;
}
else
{
//do as per requirement
singleTapActivated = FALSE;
}
}
//for zooming after double tapping
- (void)scrollViewDoubleTapped:(UITapGestureRecognizer*)recognizer
{
//to check whether image is zoomed
if (self.zoomScale != 1.0f)
{
//if image is zoomed, then zoom out
[self setZoomScale:1.0 animated:YES];
self.imageView.frame = CGRectMake( (self.frame.size.width - finalPhotoWidth) / 2, (self.frame.size.height - finalPhotoHeight)/2, finalPhotoWidth, finalPhotoHeight);
[self.observer photoZoomStopped];
}
else
{
// get the point of image which is double tapped
CGPoint pointInView = [recognizer locationInView:self.imageView];
// Get a zoom scale that's zoomed in slightly, capped at the maximum zoom scale specified by the scroll view
CGFloat newZoomScale = self.zoomScale * 4.0f;
newZoomScale = MIN(newZoomScale, self.maximumZoomScale);
// Figure out the rect we want to zoom to, then zoom to it
CGSize scrollViewSize = self.imageView.frame.size;
CGFloat w = scrollViewSize.width / newZoomScale;
CGFloat h = scrollViewSize.height / newZoomScale;
CGFloat x = pointInView.x - (w / 2.0f);
CGFloat y = pointInView.y - (h / 2.0f);
CGRect rectToZoomTo = CGRectMake(x, y, w, h);
[self zoomToRect:rectToZoomTo animated:YES];
}
}
// To re-center the image after zooming in and zooming out
- (void)centerScrollViewContents
{
CGSize boundsSize = self.bounds.size;
CGRect contentsFrame = self.imageView.frame;
if (contentsFrame.size.width < boundsSize.width)
{
contentsFrame.origin.x = (boundsSize.width - contentsFrame.size.width) / 2.0f;
}
else
{
contentsFrame.origin.x = 0.0f;
}
if (contentsFrame.size.height < boundsSize.height)
{
contentsFrame.origin.y = (boundsSize.height - contentsFrame.size.height) / 2.0f;
}
else
{
contentsFrame.origin.y = 0.0f;
}
self.imageView.frame = contentsFrame;
}
//for zooming in and zooming out
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
if (self.zoomScale > 1.0f)
{
[self.observer photoZoomStarted];
[self centerScrollViewContents];
}
else
{
self.bouncesZoom = NO;
[self.observer photoZoomStopped];
// for zooming out by pinching
[self centerScrollViewContents];
}
// The scroll view has zoomed, so we need to re-center the contents
}
- (UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
Please let me know if it helps. Thanks :)

Passing a value from a class to a cell

In my app I'm using the PSCollectionView to create a view similar to pinterest. Now I'm trying to pass from my class to the cell class a value in which I insert the height of the imageView I set in the cell. When I run the app, the app create a cell exactly using this height, but the imageView has no dimension.
I post here my code:
PSCollectionView controller
- (CGFloat)collectionView:(PSCollectionView *)collectionView heightForRowAtIndex:(NSInteger)index {
NSString *width = [self.arrayWithData[index] objectForKey:#"width"];
NSString *height = [self.arrayWithData[index] objectForKey:#"height"];
NSLog(#"%# e %#", width, height);
cellHeight = [self getHeightWith:width andHeight:height];
return cellHeight;
}
- (CGFloat)getHeightWith:(NSString *)originalWidth andHeight:(NSString *)originalHeight {
float width = [originalWidth floatValue];
float height = [originalHeight floatValue];
float multiplier = height / width;
// So che la mia cella ha una dimensione massima in larghezza di 100, da questo calcolo l'altezza
return 100 * multiplier;
}
- (PSCollectionViewCell *)collectionView:(PSCollectionView *)collectionView cellForRowAtIndex:(NSInteger)index {
ProductViewCell *cell = (ProductViewCell *)[self.psView dequeueReusableViewForClass:nil];
if (!cell) {
//cell = [[ProductViewCell alloc]initWithFrame:CGRectMake(10, 70, 100, 100)];
//cell = [[ProductViewCell alloc] initWithFrame:CGRectMake(0,0,collectionView.frame.size.width/2,100)];
cell = [[ProductViewCell alloc] initWithFrame:CGRectMake(0,0,collectionView.frame.size.width/2,cellHeight + 20)];
}
cell.imageHeight = cellHeight;
cell.labelName.text = [[self.arrayWithData objectAtIndex:index]objectForKey:#"name"];
NSURL * url = [NSURL URLWithString:[[self.arrayWithData objectAtIndex:index]objectForKey:#"url"]];
[self loadImageFromWeb:url andImageView:cell.productImage];
return cell;
}
- (void) loadImageFromWeb:(NSURL *)urlImg andImageView:(UIImageView *)imageView {
//NSURLRequest* request = [NSURLRequest requestWithURL:url];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:urlImg];
NSString *authCredentials =#"reply:reply";
NSString *authValue = [NSString stringWithFormat:#"Basic %#",[authCredentials base64EncodedStringWithWrapWidth:0]];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (!error){
UIImage *image = [[UIImage alloc] initWithData:data];
[imageView setImage:image];
[HUD hide:YES];
} else {
NSLog(#"ERRORE: %#", error);
}
}];
}
and this code:
ProductViewCell.h
#import "PSCollectionViewCell.h"
#interface ProductViewCell : PSCollectionViewCell {
float wMargin;
}
#property(nonatomic,strong)UIImageView *productImage;
#property(nonatomic,strong)UILabel *labelName;
// I use this variable to pass the height of the cell from the class who implement PSCollectionView
#property CGFloat imageHeight;
+ (CGFloat)heightForViewWithObject:(id)object inColumnWidth:(CGFloat)cloumnWidth;
#end
ProductViewCell.m
#import "ProductViewCell.h"
#define MARGIN 8.0
#implementation ProductViewCell
- (id)initWithFrame:(CGRect)frame
{
wMargin = 5.0;
self = [super initWithFrame:frame];
if (self) {
// self.productImage = [[UIImageView alloc]initWithFrame:CGRectMake(wMargin, 5, frame.size.width - (wMargin * 2), 125)];
self.productImage = [[UIImageView alloc]initWithFrame:CGRectMake(wMargin, 5, frame.size.width - (wMargin * 2), self.imageHeight)];
self.labelName = [[UILabel alloc]initWithFrame:CGRectMake(wMargin, 130, frame.size.width - (wMargin * 2), 20)];
self.labelName.font = [self.labelName.font fontWithSize:12];
self.labelName.textAlignment = NSTextAlignmentCenter;
[self addSubview:self.productImage];
[self addSubview:self.labelName];
self.backgroundColor = [UIColor colorWithRed:236.0f/255.0f green:236.0f/255.0f blue:236.0f/255.0f alpha:1.0];
self.layer.masksToBounds = YES;
self.layer.borderWidth = 1.0f;
self.layer.cornerRadius = 10.0f;
self.layer.borderColor= [[UIColor colorWithRed:207.0f/255.0f green:207.0f/255.0f blue:207.0f/255.0f alpha:1] CGColor];
[self.productImage setContentMode:UIViewContentModeScaleAspectFit];
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
When I try to log the value of self.imageHeight it shows in the console a 0, but you can see that I set this data to cellHeight in the PSCollectionView controller.
How I can send the data I calculate to my cell? There's a way to do that?
According to the provided code, the class property imageHeight in the ProductViewCell implementation is only used when a new cell is initialized. At that time the imageHeight has never been set or updated, so it will always be 0.
This means whenever you update the value for imageHeight, the cell property will be updated, but the cell won't do anything with it.
To achieve that you can simply override the setImageHeight: method in ProductViewCell to be able to trigger some action.
- (void)setImageHeight:(CGFloat)imageHeight {
if (_imageHeight != imageHeight) {
_imageHeight = imageHeight;
// Do something useful with the new value e.g. calculations
}
}
This method will be called every time you update the cell property
cell.imageHeight = ...
Finally I did it without using setter! The solution is simply to use the frame.size.height. My cell code is the following:
- (id)initWithFrame:(CGRect)frame
{
wMargin = 5.0;
self = [super initWithFrame:frame];
if (self) {
self.productImage = [[UIImageView alloc]initWithFrame:CGRectMake(wMargin, 5, frame.size.width - (wMargin * 2), frame.size.height)];
self.labelName = [[UILabel alloc]initWithFrame:CGRectMake(wMargin, frame.size.height, frame.size.width - (wMargin * 2), 20)];
self.labelName.font = [self.labelName.font fontWithSize:12];
self.labelName.textAlignment = NSTextAlignmentCenter;
[self addSubview:self.productImage];
[self addSubview:self.labelName];
self.backgroundColor = [UIColor colorWithRed:236.0f/255.0f green:236.0f/255.0f blue:236.0f/255.0f alpha:1.0];
self.layer.masksToBounds = YES;
self.layer.borderWidth = 1.0f;
self.layer.cornerRadius = 10.0f;
self.layer.borderColor= [[UIColor colorWithRed:207.0f/255.0f green:207.0f/255.0f blue:207.0f/255.0f alpha:1] CGColor];
[self.productImage setContentMode:UIViewContentModeScaleAspectFit];
}
return self;
}
I simply used the frame.size.height to define the height of my imageView and following you can see the result:

Reset UIScrollView to new frame dimensions after orientation change

I have an ImageZoom class that subclasses UIView and is a delgate for the UIScrollView. It's pretty straight forward. The class contains a UIScrollView which contains a UIImageView. When an instance of the class is added to a view controller the image is zoomed so that it is flush with the view. There is a method that zooms in when you double tap and zooms out when repeated. Everything works great except for when I change orientation to landscape. I can't seem to figure out how to get the zoom right so that the image is now flush with the new orientation. Here is a link to file as well:
http://www.2shared.com/file/bowDjzLr/imagescroll.html
ViewController.h
#import <UIKit/UIKit.h>
#import "ImageZoom.h"
#interface ViewController : UIViewController
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic,strong) ImageZoom *imageZoom;
#property (nonatomic, strong) UIImage *image;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.image = [UIImage imageNamed:#"1.png"];
}
-(void)viewDidAppear:(BOOL)animated
{
ImageZoom *imageZoom = [[ImageZoom alloc]initWithImage:self.image andFrame:self.view.bounds];
self.imageZoom = imageZoom;
[self.view addSubview:imageZoom];
}
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[self.imageZoom willAnimateToFrame:self.view.bounds];
}
#end
ImageZoom.h
#import <UIKit/UIKit.h>
#interface ImageZoom : UIView <UIScrollViewDelegate>
- (id)initWithImage:(UIImage *)image andFrame:(CGRect)frame;
-(void)willAnimateToFrame:(CGRect)frame;
#end
ImageZoom.m
#import "ImageZoom.h"
#interface ImageZoom ()
#property (nonatomic, strong) UIImage *image;
#property (nonatomic, strong) UIImageView *imageView;
#property (nonatomic, strong) UIScrollView *scrollView;
#property BOOL zoomed;
#end
#implementation ImageZoom
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self loadContent];
}
return self;
}
-(void)loadContent
{
self.scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
self.scrollView.delegate = self;
self.scrollView.contentSize = self.image.size;
[self.scrollView addSubview:self.imageView];
[self addSubview:self.scrollView];
CGRect scrollViewFrame = self.scrollView.frame;
CGFloat scaleWidth = scrollViewFrame.size.width / self.scrollView.contentSize.width;
CGFloat scaleHeight = scrollViewFrame.size.height / self.scrollView.contentSize.height;
CGFloat minScale = MIN(scaleWidth, scaleHeight);
self.scrollView.minimumZoomScale = minScale;
self.scrollView.maximumZoomScale = 1;
self.scrollView.zoomScale = minScale;
UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(scrollViewDoubleTapped:)];
doubleTapRecognizer.numberOfTapsRequired = 2;
doubleTapRecognizer.numberOfTouchesRequired = 1;
[self.scrollView addGestureRecognizer:doubleTapRecognizer];
}
-(void)willAnimateToFrame:(CGRect)frame
{
self.scrollView.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
CGRect scrollViewFrame = self.scrollView.frame;
CGFloat scaleWidth = scrollViewFrame.size.width / self.scrollView.contentSize.width;
CGFloat scaleHeight = scrollViewFrame.size.height / self.scrollView.contentSize.height;
CGFloat minScale = MIN(scaleWidth, scaleHeight);
self.scrollView.minimumZoomScale = minScale;
self.scrollView.maximumZoomScale = 1;
self.scrollView.zoomScale = minScale;
CGPoint centerPoint = CGPointMake(CGRectGetMidX(self.scrollView.frame), CGRectGetMidY(self.scrollView.frame));
[self view:self.imageView setCenter:centerPoint];
}
- (void)view:(UIView*)view setCenter:(CGPoint)centerPoint
{
CGRect viewFrame = view.frame;
CGPoint scrollViewContentOffset = self.scrollView.contentOffset;
CGFloat x = centerPoint.x - viewFrame.size.width / 2.0;
CGFloat y = centerPoint.y - viewFrame.size.height / 2.0;
if(x < 0)
{
scrollViewContentOffset.x = -x;
viewFrame.origin.x = 0.0;
}
else
{
viewFrame.origin.x = x;
}
if(y < 0)
{
scrollViewContentOffset.y = -y;
viewFrame.origin.y = 0.0;
}
else
{
viewFrame.origin.y = y;
}
view.frame = viewFrame;
self.scrollView.contentOffset = scrollViewContentOffset;
self.zoomed = NO;
}
- (id)initWithImageView:(UIImageView *)imageView andFrame:(CGRect)frame
{
self.image = imageView.image;
self.imageView = imageView;
return [self initWithFrame:frame];
}
- (id)initWithImage:(UIImage *)image andFrame:(CGRect)frame
{
self.image = image;
self.imageView = [[UIImageView alloc] initWithImage:self.image];
return [self initWithFrame:frame];
}
- (UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
- (void)scrollViewDidZoom:(UIScrollView *)sv
{
UIView* zoomView = [sv.delegate viewForZoomingInScrollView:sv];
CGRect zoomViewFrame = zoomView.frame;
if(zoomViewFrame.size.width < sv.bounds.size.width)
{
zoomViewFrame.origin.x = (sv.bounds.size.width - zoomViewFrame.size.width) / 2.0;
}
else
{
zoomViewFrame.origin.x = 0.0;
}
if(zoomViewFrame.size.height < sv.bounds.size.height)
{
zoomViewFrame.origin.y = (sv.bounds.size.height - zoomViewFrame.size.height) / 2.0;
}
else
{
zoomViewFrame.origin.y = 0.0;
}
zoomView.frame = zoomViewFrame;
}
- (void)scrollViewDoubleTapped:(UITapGestureRecognizer*)recognizer
{
if(self.zoomed==NO)
{
CGPoint pointInView = [recognizer locationInView:self.imageView];
CGSize scrollViewSize = self.scrollView.bounds.size;
CGFloat w = scrollViewSize.width / self.scrollView.maximumZoomScale;
CGFloat h = scrollViewSize.height / self.scrollView.maximumZoomScale;
CGFloat x = pointInView.x - (w / 2.0);
CGFloat y = pointInView.y - (h / 2.0);
CGRect rectToZoomTo = CGRectMake(x, y, w, h);
[self.scrollView zoomToRect:rectToZoomTo animated:YES];
self.zoomed = YES;
}
else if(self.zoomed == YES)
{
CGRect rectToZoomTo = CGRectMake(0, 0, self.scrollView.contentSize.width, self.scrollView.contentSize.height);
[self.scrollView zoomToRect:rectToZoomTo animated:YES];
self.zoomed = NO;
}
}
#end
It has something to do with the willAnimateToFrame method that is called when the viewController changes orientation. Any help would be greatly appreciated.
Got it working in case anyone is interested. I had to make some changes to my ImageZoom.m file:
#import "ImageZoom.h"
#interface ImageZoom ()
#property (nonatomic, strong) UIImage *image;
#property (nonatomic, strong) UIImageView *imageView;
#property (nonatomic, strong) UIScrollView *scrollView;
#property BOOL zoomed;
#end
#implementation ImageZoom
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self loadContentWithFrame:frame];
}
return self;
}
-(void)loadContentWithFrame:(CGRect)frame
{
self.scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, frame.size.width, frame.size.height)];
self.scrollView.delegate = self;
self.scrollView.contentSize = self.image.size;
self.backgroundColor = [UIColor redColor];
[self.scrollView addSubview:self.imageView];
[self addSubview:self.scrollView];
CGRect scrollViewFrame = self.scrollView.frame;
CGFloat scaleWidth = scrollViewFrame.size.width / self.scrollView.contentSize.width;
CGFloat scaleHeight = scrollViewFrame.size.height / self.scrollView.contentSize.height;
CGFloat minScale = MIN(scaleWidth, scaleHeight);
self.scrollView.minimumZoomScale = minScale;
self.scrollView.maximumZoomScale = 1;
self.scrollView.zoomScale = minScale;
UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(scrollViewDoubleTapped:)];
doubleTapRecognizer.numberOfTapsRequired = 2;
doubleTapRecognizer.numberOfTouchesRequired = 1;
[self.scrollView addGestureRecognizer:doubleTapRecognizer];
self.zoomed = NO;
}
-(void)willAnimateToFrame:(CGRect)frame
{
self.frame = frame;
[self loadContentWithFrame:frame];
}
- (id)initWithImageView:(UIImageView *)imageView andFrame:(CGRect)frame
{
self.image = imageView.image;
self.imageView = imageView;
return [self initWithFrame:frame];
}
- (id)initWithImage:(UIImage *)image andFrame:(CGRect)frame
{
self.image = image;
self.imageView = [[UIImageView alloc] initWithImage:self.image];
return [self initWithFrame:frame];
}
- (UIView*)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
- (void)scrollViewDidZoom:(UIScrollView *)sv
{
UIView* zoomView = [sv.delegate viewForZoomingInScrollView:sv];
CGRect zoomViewFrame = zoomView.frame;
if(zoomViewFrame.size.width < sv.bounds.size.width)
{
zoomViewFrame.origin.x = (sv.bounds.size.width - zoomViewFrame.size.width) / 2.0;
}
else
{
zoomViewFrame.origin.x = 0.0;
}
if(zoomViewFrame.size.height < sv.bounds.size.height)
{
zoomViewFrame.origin.y = (sv.bounds.size.height - zoomViewFrame.size.height) / 2.0;
}
else
{
zoomViewFrame.origin.y = 0.0;
}
zoomView.frame = zoomViewFrame;
}
- (void)scrollViewDoubleTapped:(UITapGestureRecognizer*)recognizer
{
if(self.zoomed==NO)
{
CGPoint pointInView = [recognizer locationInView:self.imageView];
CGSize scrollViewSize = self.scrollView.bounds.size;
CGFloat w = scrollViewSize.width / self.scrollView.maximumZoomScale;
CGFloat h = scrollViewSize.height / self.scrollView.maximumZoomScale;
CGFloat x = pointInView.x - (w / 2.0);
CGFloat y = pointInView.y - (h / 2.0);
CGRect rectToZoomTo = CGRectMake(x, y, w, h);
[self.scrollView zoomToRect:rectToZoomTo animated:YES];
self.zoomed = YES;
}
else if(self.zoomed == YES)
{
CGRect rectToZoomTo = CGRectMake(0, 0, self.scrollView.contentSize.width, self.scrollView.contentSize.height);
[self.scrollView zoomToRect:rectToZoomTo animated:YES];
self.zoomed = NO;
}
}
#end

Adding subviews to a UIView at initialization

In the initialization method for a UIView subclass I am adding several UIImageViews. When the view is rendered they are present in the subviews array and have valid frame rects, but are not drawn on the screen. Does anyone know why this happens?
- (id) initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (!self)
return nil;
[self commonInit];
return self;
}
- (void) commonInit {
_padding = 128.0f;
// Add the chord views here
_chordImages = [NSArray arrayWithObjects:[UIImage imageNamed:#"fn_maj_x_x_x_x_1_e_1_fn"], [UIImage imageNamed:#"en_maj_x_x_x_x_1_e_1_en"], [UIImage imageNamed:#"dn_maj_x_x_x_x_1_d_1_f#"], [UIImage imageNamed:#"an_min_x_x_x_x_1_a_1_en"], nil];
CGFloat containerWidth = [self bounds].size.width;
NSLog(#"containerWidth: %f",containerWidth);
CGFloat chordWidth = [[_chordImages objectAtIndex:0] size].width;
NSLog(#"chordWidth: %f",chordWidth);
CGFloat chordMarkerWidth = [[[GVChordMarkerView alloc] initWithFrame:CGRectMake(0, 0, 12, 12)] frame].size.width;
NSLog(#"chordMarkerWidth: %f",chordMarkerWidth);
// [self setFrame:CGRectMake(chordXPosition, 0, [self bounds].size.width, [self bounds].size.height]);
CGFloat chordXPosition = 0;
CGFloat chordXSpacing = (containerWidth/4 - (chordMarkerWidth + chordWidth));
chordXPosition += containerWidth/4;
for (NSUInteger i = 0; i < [_chordImages count]; i++) {
chordXPosition += chordXSpacing;
CGRect chordImageViewFrame = CGRectMake(chordXPosition, 0, [[_chordImages objectAtIndex:0] size].width, [[_chordImages objectAtIndex:0] size].height);
UIImageView *chordImageView = [[UIImageView alloc] initWithFrame:chordImageViewFrame];
[self addSubview:chordImageView];
chordXPosition += (chordMarkerWidth + chordWidth);
}
NSLog(#"Finished");
}
Could it be that your UIImageview is just empty? Where did you add the image?

Resources