UITableView Layout is Broken - ios

I'm new to iOS development, and now working on an iOS app mainly using UINavigationController and UITableViewController.
The problem I try to solve is the UITableView (Custom tableView cell) layout broken bug on the root viewController. This happens when I back from a child viewController to the root viewController.(Left: Original, Right: Wrong Layout) It looks like UITableView position is moved for some reason, but I'm not sure why.
In MainViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
viewFrame = self.view.bounds;
[self loadHeader];
[self loadTable];
self.view.backgroundColor = [UIColor whiteColor];
numberOfCellRow = 20;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:YES];
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
- (void)loadView {
[super loadView];
}
- (void)loadHeader {
CGRect headerFrame = viewFrame;
headerFrame.size.width = self.view.frame.size.width;
headerFrame.size.height = 200;
self.headerView = [[HeaderView alloc] initWithFrame:CGRectIntegral(headerFrame)];
[self.view addSubview:self.headerView];
NSLog(#"header loaded");
}
- (void)loadTable {
CGRect tableFrame = CGRectMake(viewFrame.origin.x, viewFrame.origin.y + 150,
viewFrame.size.width, viewFrame.size.height-150);
self.customTableView = [[UITableView alloc] initWithFrame:CGRectIntegral(tableFrame)];
self.customTableView.backgroundColor = [UIColor clearColor];
//set delegates
self.customTableView.delegate = self;
self.customTableView.dataSource = self;
//set custom cell
UINib *nib = [UINib nibWithNibName:#"CardViewCell" bundle:nil];
[self.customTableView registerNib:nib forCellReuseIdentifier:#"Cell"];
self.customTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.view addSubview:self.customTableView];
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"cell loaded");
dispatch_async(dispatch_get_main_queue(), ^{
[self loadData:indexPath];
});
}
- (void)loadData: (NSIndexPath *)indexPath {
_tableCell.titleLabel.text = [[_articles objectAtIndex:indexPath.row] title];
NSLog(#"%#", [[_articles objectAtIndex:indexPath.row] title]);
[_tableCell setNeedsLayout];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
_tableCell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
_tableCell.backgroundColor = [UIColor clearColor];
[_tableCell.contentView setUserInteractionEnabled: NO];
// add touch events
[_tableCell.button addTarget:self
action:#selector(cellPressed:withEvent:)
forControlEvents:UIControlEventTouchUpInside];
NSLog(#"%#", NSStringFromCGRect(tableView.frame));
return _tableCell;
}
In CardViewCell.m
- (void)drawRect:(CGRect)rect {
//self.backgroundColor = [UIColor colorWithRed:228/255.0f green:228/255.0f blue:228/255.0f alpha:1.0f];
NSLog(#"%f", rect.origin.x);
self.backgroundColor = [UIColor clearColor];
[self drawCardView];
[self drawCardImage];
[self drawButton];
[self drawLabels];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
self.selectionStyle = UITableViewCellSelectionStyleNone;
}
- (void)drawCardImage {
_cardViewBounds = _cardView.bounds;
CGRect imageFrame = _cardViewBounds;
imageFrame.size.height = _cardViewBounds.size.height/2+40;
_cardImage = [[UIImageView alloc] initWithFrame:CGRectIntegral(imageFrame)];
_cardImage.image = [UIImage imageNamed:#"sampleImage"];
_cardImage.backgroundColor = [UIColor grayColor];
_cardImage.clipsToBounds = YES;
_cardImage.contentMode = UIViewContentModeScaleAspectFill;
_cardImage.userInteractionEnabled = YES;
_cardImage.tag = 100;
UIBezierPath *maskPath;
maskPath = [UIBezierPath bezierPathWithRoundedRect:self.cardView.bounds
byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight)
cornerRadii:CGSizeMake(3.0, 3.0)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = self.cardView.bounds;
maskLayer.path = maskPath.CGPath;
_cardImage.layer.mask = maskLayer;
[self.cardView addSubview:_cardImage];
}
- (void)drawCardView {
CGRect screen = [[UIScreen mainScreen] bounds];
CGRect frame = CGRectMake(15, 25, (int)screen.size.width-30, 200);
_cardView.layer.cornerRadius = 3;
_cardView.backgroundColor = [UIColor greenColor];
_cardImage.userInteractionEnabled = YES;
_cardImage.tag = 101;
_cardView.frame = CGRectIntegral(frame);
CALayer *caLayer = _cardView.layer;
caLayer.frame = _cardView.frame;
caLayer.shadowRadius = 3.0f;
caLayer.shadowOpacity = 0.4f;
caLayer.shadowOffset = CGSizeMake(0.0f, 3.0f);
caLayer.shouldRasterize = YES;
// retina screen resolution
[caLayer setRasterizationScale:[[UIScreen mainScreen] scale]];
[caLayer setShouldRasterize:YES];
[self addSubview:_cardView];
}
- (void)drawButton {
CGRect buttonSize = CGRectMake(_cardViewBounds.size.width-100, _cardViewBounds.size.height/2+10, 50, 50);
_button = [[UIButton alloc] initWithFrame:CGRectIntegral(buttonSize)];
_button.layer.cornerRadius = 25;
_button.backgroundColor = [UIColor colorWithRed:0 green:169.0f/255.0f blue:244.0f/255.0f alpha:1.0f];
_button.userInteractionEnabled = YES;
_button.tag = 102;
//_button.titleLabel.text = #"+";
[_button setTitle:#"+" forState:UIControlStateNormal];
[_button.titleLabel setFont:[UIFont fontWithName:#"Helvetica" size:30.0]];
CALayer *caButtonLayer = _button.layer;
caButtonLayer.frame = _button.frame;
caButtonLayer.shadowRadius = 3.0f;
caButtonLayer.shadowOpacity = 0.2f;
caButtonLayer.shadowOffset = CGSizeMake(0.0f, 3.0f);
caButtonLayer.shouldRasterize = YES;
// retina screen resolution
[caButtonLayer setRasterizationScale:[[UIScreen mainScreen] scale]];
[caButtonLayer setShouldRasterize:YES];
[self.cardView addSubview:_button];
}
- (void)drawLabels {
CGRect titleLabelSize = CGRectMake( 10, _cardViewBounds.size.height-50, _cardViewBounds.size.width-20, 40);
_titleLabel = [[UILabel alloc] initWithFrame:CGRectIntegral(titleLabelSize)];
_titleLabel.backgroundColor = [UIColor clearColor];
_titleLabel.numberOfLines = 2;
_titleLabel.userInteractionEnabled = YES;
_titleLabel.tag = 103;
[_titleLabel setFont:[UIFont fontWithName:#"Helvetica" size:15.0]];
[_cardView addSubview:_titleLabel];
[_cardView sendSubviewToBack:_titleLabel];
}
- (void)prepareForReuse {
[super prepareForReuse];
for (UIView *subView in [self.contentView subviews]) {
[subView removeFromSuperview];
}
}
The code of this app is on this link.
Any ideas to solve this?
Your thoughts and help will be hugely appreciated.

the reason the view misplace is due to the _cardView.frame is CGRectZero when disappear, and I didn't find the solve yet.
you can add those to see the change.
-(void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
NSLog(#"viewWillLayoutSubviews cardView %#",NSStringFromCGRect(self.tableCell.cardView.frame));
}
-(void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
NSLog(#"viewDidLayoutSubviews cardView %#",NSStringFromCGRect(self.tableCell.cardView.frame));
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
NSLog(#"viewWillDisappear cardView %#",NSStringFromCGRect(self.tableCell.cardView.frame));
}
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
NSLog(#"viewDidDisappear cardView %#",NSStringFromCGRect(self.tableCell.cardView.frame));
}
I think you can learn more about life-cycle about viewController and Cell.
LifeCycle
by the way, when I watching your code, I don't know if you want to use xib or only code to programming. Like the code below, this is init from code but you try to get from xib.
just my opinion.
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
// make self from nib file
UINib *nib = [UINib nibWithNibName:#"HeaderView" bundle:nil];
self = [nib instantiateWithOwner:nil options:nil][0];
self.backgroundColor = [UIColor colorWithRed:0 green:169.0f/255.0f blue:244.0f/255.0f alpha:1.0f];
CGRect frame = CGRectZero;
frame.size.width = [[UIScreen mainScreen] bounds].size.width;
frame.size.height = 200;
[self setFrame:frame];
}
return self;
}

Related

UIActivityIndicatorView showing and causing crash on two specific views

I am getting a very hard to trace crash in one of my views that is related to UIActivityIndicatorViewSometimes it crashes right away, sometimes it takes a few loads (going back to the previous view in the navigation stack and loading the view again). I have run the app through instruments, and while memory use keeps rising, I don't see any leaks. Could I be running out of memory? I also don't see any memory warnings. Here is the error:
*** -[UIActivityIndicatorView release]: message sent to deallocated instance 0x15f6d6aa0
I am not making any connections, and I can see the ActivityIndicator show up and then the app crashes when it disappears (or it disappears before the app crashes).
I have read that AFNetworking can cause this problem, but I am not using it. I am just using NSURLSession.
Both classes are very similar, and I have included the loading calls of one, as the class is too big to post here.
It is displayed in a Navigation Controller nested in a TabBarController:
- (BOOL)prefersStatusBarHidden {
return NO;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.userDefaults = [NSUserDefaults standardUserDefaults];
self.hairlineHeightConstraint.constant = 0.5f;
self.hairlineDivider.backgroundColor = [UIColor colorWithWhite:0.9f alpha:1.0f];
self.title = #"Course";
[self.classroomButton setTintColor:[UIColor pxColorWithHexValue:self.passedCourse.courseColor]];
[self.classroomButton addTarget:self action:#selector(subscribeToCourse:) forControlEvents:UIControlEventTouchUpInside];
[self getAnySubscribedCourse];
if (self.subscribedCourse) {
if (self.passedCourse == self.subscribedCourse) {
[self.classroomButton setTitle:#"Remove from Classroom" forState:UIControlStateNormal];
self.subscribedToThisCourse = YES;
} else {
self.alreadySubscribed = YES;
}
}
[self configureHeaderView];
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
if (self.shareView) {
CGRect frame = self.shareView.frame;
CGFloat navbarHeight = self.navigationController.navigationBar.frame.size.height;
CGFloat statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
frame = CGRectMake(0.0f, self.tableView.contentOffset.y + statusBarHeight + navbarHeight, frame.size.width, frame.size.height);
self.shareView.frame = frame;
[self.view bringSubviewToFront:self.shareView];
}
NSString *backText = self.navigationItem.backBarButtonItem.title;
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:backText style:UIBarButtonItemStylePlain target:nil action:nil];
[backButton setTitleTextAttributes:[[MSThemeManager currentTheme] barButtonTextDictionaryForState:UIControlStateNormal withTintColor:[UIColor pxColorWithHexValue:self.passedCourse.courseColor]] forState:UIControlStateNormal];
self.navigationItem.backBarButtonItem = backButton;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.navigationController.navigationBarHidden = NO;
[self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:animated];
[self.tableView reloadData];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if ([self.tableView.tableHeaderView isKindOfClass:[ParallaxCourseDetailHeaderView class]]) {
ParallaxCourseDetailHeaderView *headerView = (ParallaxCourseDetailHeaderView *)self.tableView.tableHeaderView;
[headerView.courseInfoAudioPlayer stop];
self.tableView.tableHeaderView = nil;
}
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - HeaderView
- (void)configureHeaderView
{
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
NSDictionary *attributesDictionary = #{NSFontAttributeName : self.headerLabel.font};
CGFloat width = screenWidth - self.headerLabel.frame.origin.x - 15.0f;
CGSize boundingBox = CGSizeMake(width, CGFLOAT_MAX);
NSString *descriptionToBound = self.passedCourse.courseDescription;
CGRect labelRect = [descriptionToBound boundingRectWithSize:boundingBox
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributesDictionary
context:nil];
CGRect headerLabelRect = self.headerLabel.frame;
CGRect tableHeaderViewRect = self.tableView.tableHeaderView.frame;
CGRect dividerRect = self.hairlineDivider.frame;
CGFloat heightDifference = ceilf(labelRect.size.height - headerLabelRect.size.height);
tableHeaderViewRect.size.height += heightDifference;
self.tableView.tableHeaderView.frame = tableHeaderViewRect;
dividerRect.origin.y += heightDifference;
headerLabelRect.size.width = ceil(labelRect.size.width);
headerLabelRect.size.height = ceil(labelRect.size.height);
headerLabelRect.origin.y = (dividerRect.origin.y - headerLabelRect.size.height) / 2;
self.headerLabel.frame = headerLabelRect;
CGFloat parallaxViewHeight = 280.0f;
CGFloat headerHeight = parallaxViewHeight + heightDifference;
ParallaxCourseDetailHeaderView *headerView = [[ParallaxCourseDetailHeaderView alloc] initWithTitleViewStyle:SWParallaxTitleViewStyleWhiteWithMask withHeight:tableHeaderViewRect.size.height headerHeight:headerHeight];
UIImage *image = [UIImage imageNaobj:self.passedCourse.headerImage];
headerView.courseImage = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[headerView setTintColor:[UIColor whiteColor]];
headerView.isTitleViewOpaque = YES;
headerView.fadeInDuration = 0.0;
headerView.trackID = self.passedCourse.aboutTrackID;
[headerView courseAudioIntroControl];
UIImage *headerTeacherImage = [UIImage imageNaobj:[NSString stringWithFormat:#"%#", self.passedCourse.teacher.teacherImageID]];
self.headerTeacherImage.image = headerTeacherImage;
self.headerTeacherImage.layer.cornerRadius = self.headerTeacherImage.frame.size.height / 2;
self.headerTeacherImage.clipsToBounds = YES;
self.headerLabel.text = self.passedCourse.courseDescription;
[self.headerTeacherButton setImage:headerTeacherImage forState:UIControlStateNormal];
UIView *oldHeaderView = self.tableView.tableHeaderView;
oldHeaderView.frame = CGRectMake(0, 0, screenWidth, oldHeaderView.frame.size.height);
self.tableView.tableHeaderView = nil;
[headerView.titleView addSubview:oldHeaderView];
self.tableView.tableHeaderView = headerView;
[headerView.imageContainerView setBackgroundColor:[UIColor pxColorWithHexValue:self.passedCourse.courseColor]];
headerView.title = self.passedCourse.title;
headerView.subtitle = [NSString stringWithFormat:#"%lu Sessions", (unsigned long)self.passedCourse.courseObjects.count];
headerView.teacher = [NSString stringWithFormat:#"With %#", self.passedCourse.teacher.teacherName];
[headerView.titleLabel adjustCurrentFontSize];
[headerView.subtitleLabel adjustCurrentFontSize];
[headerView.teacherLabel adjustCurrentFontSize];
}
#pragma mark - ScrollView
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if ([self.tableView.tableHeaderView isKindOfClass:[ParallaxCourseDetailHeaderView class]]) {
ParallaxCourseDetailHeaderView *headerView = (ParallaxCourseDetailHeaderView *)self.tableView.tableHeaderView;
headerView.parallaxOffset = scrollView.contentOffset.y + scrollView.contentInset.top;
}
}

UIBezierPath Animation in UIView

I'm trying to make a animation that is done in Skype iOS application. The animation can be seen in this link Animation Section 3:Add a Contact
I tried with UIBezierPath but I can't do it. Any ideas?
Thanks!
My code
#implementation CustomView
#pragma mark - Lifecycle and initialize components
- (instancetype) initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if ( self ) {
self.alpha = 0;
[self configureCancelButton];
[self configureCollectionView];
[self addSubview:self.cancelButton];
[self addSubview:self.collectionView];
}
return self;
}
- (void) configureCancelButton {
self.cancelButton = [UIButton buttonWithType:UIButtonTypeSystem];
[self.cancelButton setTitle:#"Cancel" forState:UIControlStateNormal];
self.cancelButton.titleLabel.font = [UIFont systemFontOfSize:20];
[self.cancelButton addTarget:self action:#selector (cancelView) forControlEvents:UIControlEventTouchUpInside];
self.cancelButton.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.8];
self.cancelButton.layer.cornerRadius = 7.f;
self.frameForCancelButton = CGRectMake (self.bounds.origin.x+5, self.bounds.size.height - kCancelButtonHeight - 5, self.bounds.size.width-10, kCancelButtonHeight);
self.cancelButton.frame = CGRectMake (self.frameForCancelButton.origin.x, self.frameForCancelButton.origin.y + kAnimationOffset, self.frameForCancelButton.size.width, self.frameForCancelButton.size.height);
}
- (void) configureCollectionView {
UICollectionViewFlowLayout *layout= [[UICollectionViewFlowLayout alloc] init];
layout.itemSize = CGSizeMake(kItemSize, kItemSize);
layout.minimumInteritemSpacing = 3.0;
layout.sectionInset = UIEdgeInsetsMake(0, 7, 7, 10);
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
self.frameForCollectionView = CGRectMake(self.cancelButton.frame.origin.x, self.frame.size.height - (self.cancelButton.frame.size.height + 10 + kCollectionHeight), self.cancelButton.bounds.size.width, kCollectionHeight);
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake (self.frameForCollectionView.origin.x, self.frameForCollectionView.origin.y + kAnimationOffset, self.frameForCollectionView.size.width, self.frameForCollectionView.size.height)
collectionViewLayout:layout];
self.collectionView.backgroundColor = [UIColor colorWithWhite:1 alpha:.8];
[self.collectionView registerClass:[RAShareCell class] forCellWithReuseIdentifier:#"Cell"];
self.collectionView.delegate = self;
self.collectionView.dataSource = self;
self.collectionView.layer.cornerRadius = 7.f;
}
#pragma mark - Public Methods
- (void) present {
[UIView animateWithDuration:0.35 animations:^{
self.alpha = 1;
self.darkView.alpha = .5;
}];
[UIView animateWithDuration:1.0 delay:0.45 options:(UIViewAnimationOptions) UIViewAnimationCurveEaseInOut animations:^{
[self setupAnimation];
} completion:nil];
}
- (void) cancelView {
[UIView animateWithDuration:0.35 delay:0 options:UIViewAnimationCurveEaseInOut animations:^{
self.cancelButton.frame = CGRectMake (self.frameForCancelButton.origin.x, self.frameForCancelButton.origin.y + kAnimationOffset, self.frameForCancelButton.size.width, self.frameForCancelButton.size.height);
self.collectionView.frame= CGRectMake(self.frameForCollectionView.origin.x, self.frameForCollectionView.origin.y + kAnimationOffset, self.frameForCollectionView.size.width, self.frameForCollectionView.size.height);
} completion:^(BOOL finished) {
[self removeFromSuperview];
}];
;
}
- (void) setupAnimation {
self.cancelButton.alpha = 1;
self.collectionView.alpha = 1;
self.cancelButton.frame = self.frameForCancelButton;
self.collectionView.frame = self.frameForCollectionView;
[self addShapeLayer];
}
- (void)addShapeLayer
{
self.shapeLayer = [CAShapeLayer layer];
self.shapeLayer.path = [[self pathAtInterval:0.0] CGPath];
self.shapeLayer.fillColor = [[UIColor redColor] CGColor];
self.shapeLayer.lineWidth = 3.0;
self.shapeLayer.strokeColor = [[UIColor redColor] CGColor];
[self.collectionView.layer insertSublayer:self.shapeLayer atIndex:0];
}
- (UIBezierPath *) pathAtInterval:(NSTimeInterval) interval {
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(self.collectionView.frame.origin.x,self.collectionView.frame.origin.y)];
[path addQuadCurveToPoint:CGPointMake(self.collectionView.frame.size.width, self.collectionView.frame.origin.y) controlPoint:CGPointMake(self.collectionView.frame.size.width/2, self.collectionView.frame.origin.y-30)];
return path;
}
Your animation block does not contain any animations. You should move your setup outside of the animation block and then animate within it.
[self setupAnimation];
[UIView animateWithDuration:1.0 delay:0.45 options:(UIViewAnimationOptions) UIViewAnimationCurveEaseInOut animations:^{
// animate something
} completion:nil];
In addition to this, your intended animation does not have a linear progression, meaning that you'l want to use animateKeyframesWithDuration instead.
[UIView animateKeyframesWithDuration:1.0 delay:0.45 options:UIViewAnimationCurveEaseInOut animations:^{
for (NSInteger i = 0; i < 10; i++) {
[UIView addKeyframeWithRelativeStartTime:i/10.0
relativeDuration:1.0/10.0
animations:^{
self.shapeLayer = [self pathAtInterval:i/10.0];
}];
}
} completion:nil];
1, add the path you created to CAShaperLayer object;
2, see the "strokeStart" and "strokeEnd" properties in CAShapeLayer class;
3, add a animation which called "CABasicAnimation" to your Layer obj.

Why is the UIImageView not hiding when using a UISegmentedControl?

I have a UISegmentedControl where the first control will display the text within a UITextView while the second control displays a scrollable UIImageView.
In the initial startup, if I switch to the second control, the image displays and switching back to the first control, the image disappears and the UITextView shows.
However, when I switch to the second control the 2nd time and switch back to the first control, the image is still there and I cannot get the UITextView to show anymore.
My code has it to where the image is hidden and the text is shown in the first control, and vice versa in the second control.
Why was it working the first time, but then not working the second time I switched between controls?
What am I doing wrong?
Thanks
-(void)viewDidLoad
{
self.scrollView.delegate = self;
self.textView.text = #"THIS IS A TEST. THIS IS A TEST. THIS IS A TEST. THIS IS A TEST. THIS IS A TEST. THIS IS A TEST.";
self.textView.hidden = NO;
}
-(void)setScroller
{
CGSize scrollableSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height);
[self.scrollView setContentSize:scrollableSize];
self.imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"test.png"] ];
self.imageView.frame = CGRectMake(0, 0, self.scrollView.frame.size.width, self.view.frame.size.height);
self.scrollView.backgroundColor = [UIColor blackColor];
self.scrollView.minimumZoomScale = 1.0 ;
self.scrollView.maximumZoomScale = self.imageView.image.size.width / self.scrollView.frame.size.width;
//self.scrollView.zoomScale = 1.0;
[self.scrollView addSubview:self.imageView];
}
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
- (IBAction)segmentedControl:(UISegmentedControl *)sender
{
if (self.segmentedControl.selectedSegmentIndex == 0)
{
// Display apppropriate info for About
self.imageView.hidden = YES;
self.textView.hidden = NO;
}
else
{
self.imageView.hidden = NO;
self.textView.hidden = YES;
[self setScroller];
}
}
You should remove [self setScroller]; from the - (IBAction)segmentedControl:(UISegmentedControl *)sender method, and put it in -(void)viewDidLoad instead. You're calling [self setScroller]; every time you switch to the second segment.
Your code should look like:
-(void)viewDidLoad
{
[super viewDidLoad];
self.scrollView.delegate = self;
[self setupScroller];
}
-(void)setupScroller
{
// Set contentSize
CGSize scrollableSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height);
self.scrollView.contentSize = scrollableSize;
// Add textView
self.textView.text = #"THIS IS A TEST. THIS IS A TEST. THIS IS A TEST. THIS IS A TEST. THIS IS A TEST. THIS IS A TEST.";
self.textView.hidden = NO;
// Add ImageView
self.imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"test.png"]];
self.imageView.frame = CGRectMake(0, 0, self.scrollView.frame.size.width, self.view.frame.size.height);
self.imageView.hidden = YES;
[self.scrollView addSubview:self.imageView];
// Configure Zoom Scales and backgroundColor
self.scrollView.backgroundColor = [UIColor blackColor];
self.scrollView.minimumZoomScale = 1.0 ;
self.scrollView.maximumZoomScale = self.imageView.image.size.width / self.scrollView.frame.size.width;
}
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imageView;
}
- (IBAction)segmentedControl:(UISegmentedControl *)sender
{
if (self.segmentedControl.selectedSegmentIndex == 0)
{
// Display appropriate info for About
self.imageView.hidden = YES;
self.textView.hidden = NO;
}
else
{
self.imageView.hidden = NO;
self.textView.hidden = YES;
}
}
Your problem probably is that you creating a lot of instances of "imageView"
To solve your problem I suggest:
-(void)setScroller
{
CGSize scrollableSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height);
[self.scrollView setContentSize:scrollableSize];
if(self.imageView == nil) {
self.imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"test.png"]];
[self.scrollView addSubview:self.imageView];
}
self.imageView.frame = CGRectMake(0, 0, self.scrollView.frame.size.width, self.view.frame.size.height);
self.scrollView.backgroundColor = [UIColor blackColor];
self.scrollView.minimumZoomScale = 1.0 ;
self.scrollView.maximumZoomScale = self.imageView.image.size.width / self.scrollView.frame.size.width;
//self.scrollView.zoomScale = 1.0;
[self.imageView setNeedsDisplay];
[self.imageView setImage:[UIImage imageNamed: #"test.png"]];
}
I've put only the Alloc of the self.imageView + the addSubView to the if,
All the rest are out side,
Now it will work

EXC_BREAKPOINT when going back to view with imgview in scrollview

I call an view with an imgView inside a scrollview like this from another view
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
ImageViewController *view = [[self.menus objectAtIndex:[indexPath row]] objectForKey:#"VIEW"];
view.imgPath = [[self.menus objectAtIndex:[indexPath row]] objectForKey:#"PATH"];
[self presentViewController:view animated:YES completion:nil];
}
Then I show the image in the new view like this
-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return self.imgView;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSString *path = [[NSBundle mainBundle] pathForResource:self.imgPath ofType:#"png"];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:path];
self.imgView = [[UIImageView alloc] initWithImage:image];
self.imgView.frame = (CGRect){.origin=CGPointMake(0.0f, 0.0f), .size=image.size};
[self.scrollView addSubview:self.imgView];
self.scrollView.contentSize = image.size;
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.0f;
self.scrollView.zoomScale = minScale;
[self centerScrollViewContents];
}
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(scrollViewDoubleTapped:)];
doubleTapRecognizer.numberOfTapsRequired = 2;
doubleTapRecognizer.numberOfTouchesRequired = 1;
[self.scrollView addGestureRecognizer:doubleTapRecognizer];
UITapGestureRecognizer *twoFingerTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(scrollViewTwoFingerTapped:)];
twoFingerTapRecognizer.numberOfTapsRequired = 1;
twoFingerTapRecognizer.numberOfTouchesRequired = 2;
[self.scrollView addGestureRecognizer:twoFingerTapRecognizer];
}
- (void)centerScrollViewContents {
CGSize boundsSize = self.scrollView.bounds.size;
CGRect contentsFrame = self.imgView.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.imgView.frame = contentsFrame;
}
This all works with no problems and I can dismiss the view like this
- (IBAction)BackBtnPress:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
However when I want to go back to the image view again from didSelectRowAtIndexPath the app crashes and I get EXC_BREAKPOINT at
0x18e2756: calll 0x1a37a00 ; symbol stub for: getpid
I have tried debugging and it goes through viewWillAppear with seamingly no issues and then crashes
Any ideas on what the problem might be?
Thanks!
Edit
enabling zombies did not help, disabling arc changes nothing.
I fixed it by creating the new imageview when the row was selected instead of when the first view with the tableview was loaded, so my didselectrowatindexpath looks like this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
ImageViewController *view = [ImageViewController alloc];
view.imgPath = [[self.menus objectAtIndex:[indexPath row]] objectForKey:#"PATH"];
[self presentViewController:view animated:YES completion:nil];
}

Scrolling UIScrollView on external screen attached to an iPad

Hey. I've achieved making a programmatic UIScrollView with zooming, but now I've been trying to take the scrollable/zoomable image to an external screen if plugged in.
#implementation MapVC
UIScrollView *mapScrollView;
UIImageView *mapImageView;
UIImageView *mapImageViewEx;
CGFloat lastScale = 0;
NSMutableArray *map_List;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
mainMenuAppDelegate *del = (mainMenuAppDelegate *)[[UIApplication sharedApplication] delegate];
map_List = [[NSMutableArray alloc] init];
[map_List addObject:#"Pacific_Map.png"];
[map_List addObject:#"Atlantic_Map.png"];
CGRect mapScrollViewFrame = CGRectMake(0, 0, 1024, 768);
mapScrollView = [[UIScrollView alloc] initWithFrame:mapScrollViewFrame];
mapScrollView.backgroundColor = [UIColor blackColor];
[mapScrollView setDelegate:(id<UIScrollViewDelegate>)self];
mapScrollView.contentSize = CGSizeMake(2437, 1536);
mapScrollView.bounces = NO;
mapScrollView.bouncesZoom = NO;
mapScrollView.minimumZoomScale = .5;
mapScrollView.maximumZoomScale = 1.5;
[mapScrollView setZoomScale:mapScrollView.minimumZoomScale];
UIImage *mapImage = [UIImage imageNamed:[map_List objectAtIndex:mapNum]];
mapImageView = [[UIImageView alloc] initWithImage: mapImage];
[mapImage release];
if(exScreenEnabled==1){
UIImage *mapImageEx = [UIImage imageNamed:[map_List objectAtIndex:mapNum]];
mapImageViewEx = [[UIImageView alloc] initWithImage: mapImageEx];
[mapImageEx release];
UIView *containerExViewP = (UIView*)[del.switchExVC.view viewWithTag:9000];
[containerExViewP addSubview:mapImageViewEx];
}else{
[mapScrollView addSubview:mapImageView];
}
[self addSubview:mapScrollView];
mapImageView.userInteractionEnabled = YES;
UIImage *footerMapIMG = [UIImage imageNamed:#"footer_map_alternate.png"];
UIImageView *footerMapView = [[UIImageView alloc] initWithImage:(UIImage *)footerMapIMG];
CGRect footerMapFrame = CGRectMake(0, 686, 213, 82);
footerMapView.frame = footerMapFrame;
[self addSubview:footerMapView];
footerMapView.image = footerMapIMG;
[footerMapView release];
CGRect backBTNFrame = CGRectMake(20, 714, 140, 52);
UIButton *MAP_backButton = [[UIButton alloc] init];
MAP_backButton.frame = backBTNFrame;
UIImage *MAP_backButtonIMG = [UIImage imageNamed:#"button_back.png"];
[MAP_backButton setImage:MAP_backButtonIMG forState:UIControlStateNormal];
MAP_backButton.backgroundColor = [UIColor clearColor];
[self addSubview:MAP_backButton];
[MAP_backButton release];
[MAP_backButton addTarget:del.switchVC
action:#selector(gotoMapAndListChooser)
forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
if(exScreenEnabled==1){
return mapImageViewEx;
}else{
return mapImageView;
}
}
(Sorry I've had no luck getting that formatted to look right on this site)
If a video cable is plugged into an iPad, there's no image on the iPad, which is what I want. The image on the external screen zooms correctly when you do the gesture on the iPad, but I can't figure out how to make it scroll. Thanks in advance.
edit: I now have this -
#implementation MapVC
UIScrollView *mapScrollView;
UIImageView *mapImageView;
UIImageView *mapImageViewEx;
CGFloat lastScale = 0;
NSMutableArray *map_List;
int touchesNum = 0;
-(void)touchesBegan:(NSSet *)theTouches withEvent:(UIEvent *)event {
NSSet *touches = [event allTouches];
touchesNum=[touches count];
NSLog(#"number of touches %i", touchesNum);
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
mainMenuAppDelegate *del = (mainMenuAppDelegate *)[[UIApplication sharedApplication] delegate];
map_List = [[NSMutableArray alloc] init];
[map_List addObject:#"Pacific_Map.png"];
[map_List addObject:#"Atlantic_Map.png"];
CGRect mapScrollViewFrame = CGRectMake(0, 0, 1024, 768);
mapScrollView = [[UIScrollView alloc] initWithFrame:mapScrollViewFrame];
mapScrollView.backgroundColor = [UIColor blackColor];
[mapScrollView setDelegate:(id<UIScrollViewDelegate>)self];
mapScrollView.contentSize = CGSizeMake(2437, 1536);
mapScrollView.bounces = NO;
mapScrollView.bouncesZoom = NO;
mapScrollView.minimumZoomScale = .5;
mapScrollView.maximumZoomScale = 1.5;
[mapScrollView setZoomScale:mapScrollView.minimumZoomScale];
UIImage *mapImage = [UIImage imageNamed:[map_List objectAtIndex:mapNum]];
mapImageView = [[UIImageView alloc] initWithImage: mapImage];
[mapImage release];
if(exScreenEnabled==1){
UIImage *mapImageEx = [UIImage imageNamed:[map_List objectAtIndex:mapNum]];
mapImageViewEx = [[UIImageView alloc] initWithImage: mapImageEx];
[mapImageEx release];
UIView *containerExViewP = (UIView*)[del.switchExVC.view viewWithTag:9000];
[containerExViewP addSubview:mapImageViewEx];
}else{
[mapScrollView addSubview:mapImageView];
}
[self addSubview:mapScrollView];
mapImageView.userInteractionEnabled = YES;
UIImage *footerMapIMG = [UIImage imageNamed:#"footer_map_alternate.png"];
UIImageView *footerMapView = [[UIImageView alloc] initWithImage:(UIImage *)footerMapIMG];
CGRect footerMapFrame = CGRectMake(0, 686, 213, 82);
footerMapView.frame = footerMapFrame;
[self addSubview:footerMapView];
footerMapView.image = footerMapIMG;
[footerMapView release];
CGRect backBTNFrame = CGRectMake(20, 714, 140, 52);
UIButton *MAP_backButton = [[UIButton alloc] init];
MAP_backButton.frame = backBTNFrame;
UIImage *MAP_backButtonIMG = [UIImage imageNamed:#"button_back.png"];
[MAP_backButton setImage:MAP_backButtonIMG forState:UIControlStateNormal];
MAP_backButton.backgroundColor = [UIColor clearColor];
[self addSubview:MAP_backButton];
[MAP_backButton release];
[MAP_backButton addTarget:del.switchVC
action:#selector(gotoMapAndListChooser)
forControlEvents:UIControlEventTouchUpInside];
mapScrollView.multipleTouchEnabled = YES;
}
return self;
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
if(exScreenEnabled==1){
return mapImageViewEx;
}else{
return mapImageView;
}
}
- (void)scrollViewDidScroll:(UIScrollView *)inscrollView{
if(touchesNum==0){
CGPoint p = mapScrollView.contentOffset;
mapImageViewEx.frame = CGRectMake((p.x*-1), (p.y*-1), mapImageViewEx.frame.size.width, mapImageViewEx.frame.size.height);
}
}
- (void)dealloc {
[mapScrollView release];
[mapImageView release];
[map_List release];
[super dealloc];
}
#end
As I said below, I can now get either scroll or zooming to work separately, but zooming is all messed up if scrolling is working, because when zooming it thinks it's also scrolling. So I want to avoid it scrolling when zooming, and to do this I want to detect the number of touches, which I must be doing wrong!
Got it working with the image being on the iPad and external screen. I'll probably swap it in with a rectangular area because the image is resource heavy to be both the iPad and external screen.
#import "exGlobal.h"
#import "mapVC.h"
#import "switchVC.h"
#import "switchExVC.h"
#import "mainMenuAppDelegate.h"
#import <MobileCoreServices/MobileCoreServices.h>
#implementation MapVC
UIScrollView *mapScrollView;
UIImageView *mapImageView;
UIImageView *mapImageViewEx;
CGFloat lastScale = 0;
NSMutableArray *map_List;
static int toggleScroll = 1;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
mainMenuAppDelegate *del = (mainMenuAppDelegate *)[[UIApplication sharedApplication] delegate];
map_List = [[NSMutableArray alloc] init];
[map_List addObject:#"Pacific_Map.png"];
[map_List addObject:#"Atlantic_Map.png"];
CGRect mapScrollViewFrame = CGRectMake(0, 0, 1024, 768);
mapScrollView = [[UIScrollView alloc] initWithFrame:mapScrollViewFrame];
mapScrollView.backgroundColor = [UIColor blackColor];
[mapScrollView setDelegate:(id<UIScrollViewDelegate>)self];
mapScrollView.contentSize = CGSizeMake(2437, 1536);
mapScrollView.bounces = NO;
mapScrollView.bouncesZoom = NO;
mapScrollView.minimumZoomScale = .5;
mapScrollView.maximumZoomScale = 1.5;
[mapScrollView setZoomScale:mapScrollView.minimumZoomScale];
UIImage *mapImage = [UIImage imageNamed:[map_List objectAtIndex:mapNum]];
mapImageView = [[UIImageView alloc] initWithImage: mapImage];
[mapImage release];
if(exScreenEnabled==1){
UIImage *mapImageEx = [UIImage imageNamed:[map_List objectAtIndex:mapNum]];
mapImageViewEx = [[UIImageView alloc] initWithImage: mapImageEx];
[mapImageEx release];
UIView *containerExViewP = (UIView*)[del.switchExVC.view viewWithTag:9000];
[containerExViewP addSubview:mapImageViewEx];
[mapScrollView addSubview:mapImageView]; // see if this works ok on iPad. Map on TV AND iPad.
}else{
[mapScrollView addSubview:mapImageView];
}
[self addSubview:mapScrollView];
mapImageView.userInteractionEnabled = YES;
UIImage *footerMapIMG = [UIImage imageNamed:#"footer_map_alternate.png"];
UIImageView *footerMapView = [[UIImageView alloc] initWithImage:(UIImage *)footerMapIMG];
CGRect footerMapFrame = CGRectMake(0, 686, 213, 82);
footerMapView.frame = footerMapFrame;
[self addSubview:footerMapView];
footerMapView.image = footerMapIMG;
[footerMapView release];
CGRect backBTNFrame = CGRectMake(20, 714, 140, 52);
UIButton *MAP_backButton = [[UIButton alloc] init];
MAP_backButton.frame = backBTNFrame;
UIImage *MAP_backButtonIMG = [UIImage imageNamed:#"button_back.png"];
[MAP_backButton setImage:MAP_backButtonIMG forState:UIControlStateNormal];
MAP_backButton.backgroundColor = [UIColor clearColor];
[self addSubview:MAP_backButton];
[MAP_backButton release];
[MAP_backButton addTarget:del.switchVC
action:#selector(gotoMapAndListChooser)
forControlEvents:UIControlEventTouchUpInside];
mapScrollView.multipleTouchEnabled = YES;
}
return self;
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
return mapImageView;
}
-(void)scrollViewDidZoom:(UIScrollView *)scrollView {
if(exScreenEnabled==1){
CGPoint p = mapScrollView.contentOffset;
mapImageViewEx.frame = CGRectMake((p.x*-1), (p.y*-1), mapImageView.frame.size.width, mapImageView.frame.size.height);
}
}
- (void)scrollViewDidScroll:(UIScrollView *)inscrollView{
if(exScreenEnabled==1 && toggleScroll==1){
CGPoint p = mapScrollView.contentOffset;
mapImageViewEx.frame = CGRectMake((p.x*-1), (p.y*-1), mapImageView.frame.size.width, mapImageView.frame.size.height);
}
}
- (void)scrollViewWillBeginZooming:(UIScrollView *)theScrollView withView:(UIView *)view{
NSLog(#"BEGIN ZOOMING");
toggleScroll=0;
}
- (void)scrollViewDidEndZooming:(UIScrollView *)theScrollView withView:(UIView *)view atScale:(float)scale{
NSLog(#"END ZOOMING");
toggleScroll=1;
}
- (void)dealloc {
[mapScrollView release];
[mapImageView release];
[map_List release];
[super dealloc];
}
#end
I pressed the space bar (4) times for code, and NOPE doesn't work stack overflow still broken. :)

Resources