Add UIViewController as subview of UIScrollView - ios

I am building an app with some scrolling inside. In short, this is my configuration:
1) class_1: a view with a set of elements inside (something similar to camera row) listed by using a collection view
2) class_2: a modal view called by class_1 where I show each singular element selected (from class_1). Inside the same class I have also implemented the horizontal scroll of all the elements
3) class_3: a simple viewcontroller with an imageview inside which will contain the element I will show in class_2
Running my app looks like class_3 is not added as subview of class_2 and all the singular content I try to load are not visible.
Below is my class_2 code
Interface:
#import <UIKit/UIKit.h>
#import "class_3.h"
#interface class_2 : UIViewController
#property (strong, nonatomic) IBOutlet UIPageControl *pageControl;
#property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
#property (weak, nonatomic) NSArray *imageList;
#end
Implementation:
#interface class_2 () {
NSMutableArray *_viewControllers;
}
- (void)loadScrollViewWithImage:(NSUInteger)indexImage;
#end
#implementation class_2
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// _imageList is passed from class_1 when I call class_2. Contains an array of images
self.pageControl.numberOfPages = [_imageList count];
self.pageControl.currentPage = 0;
// I store inside an array N objects as the number f images I have to show. At the beginning the array has only null objects, then it will contains the views based on the images I have scrolled.
//I am storying my images inside a view because maybe I will show more controls and not just the image. It will be much easier manage them.
_viewControllers = [[NSMutableArray alloc] init];
for (NSUInteger i = 0; i < [_imageList count]; i++) {
[_viewControllers addObject:[NSNull null]];
}
// I set some properties of my scrollview defined as outlet
self.scrollView.frame = CGRectMake(0, 0, 320, 345);
self.scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.scrollView.frame) * [_imageList count], CGRectGetHeight(self.scrollView.frame));
self.scrollView.pagingEnabled = YES;
// this is set to NO, I switched to YES just now for debug (at least I can see how big the area is since there are no images visible)
self.scrollView.showsHorizontalScrollIndicator = YES;
self.scrollView.showsVerticalScrollIndicator = NO;
self.scrollView.scrollsToTop = NO;
self.scrollView.delegate = self;
// for testing now I always take the first and second elements of my array. I load both so when I move from the first image to the second is already there and there is no gap/flashing effect
[self loadScrollViewWithImage:0];
[self loadScrollViewWithImage:1];
}
#pragma mark - Private methods
- (void)loadScrollViewWithImage:(NSUInteger)indexImage {
// I scrolled until the last image, from here I can only go back
if (indexImage >= [_imageList count])
return;
// I replace the placeholder (null) object
class_3 *controller = [_viewControllers objectAtIndex:indexImage];
if ((NSNull *)controller == [NSNull null]) {
controller = [[class_3 alloc] init];
[_viewControllers replaceObjectAtIndex:indexImage withObject:controller];
}
// I add the controller's view to the scroll view - in case this is the first time I'm scrolling this image
if (controller.view.superview == nil) {
// I set my controller frame as the scrollview works as container
CGRect frame = self.scrollView.frame;
frame.origin.x = CGRectGetWidth(frame) * indexImage;
frame.origin.y = 0;
controller.view.frame = frame;
// I finally add my viewcontroller as child of my superview and subview of the scrollview
[self addChildViewController:controller];
[self.scrollView addSubview:controller.view];
[controller didMoveToParentViewController:self];
// I set an image corrisponding with the element selected from class_1
controller.imageView.image = [_imageList objectAtIndex:indexImage]
// I also tried with a fake image...just in case. No one of them is visible
//controller.imageView.image = [UIImage imageNamed:#"tempPhoto"];
}
}
My class_3 is a viewcontroller which hosts only an image view shoulb be populated with the corresponding image selezted before.
The pagecontroller is used to show where I scrolling (letf/right) and how many elements there are. The scrolling is phisically managed with the scrollview.
Here is my class_3 definition
Interface:
#import <UIKit/UIKit.h>
#import "class_3.h"
#interface class_3 : UIViewController
#property (strong, nonatomic) IBOutlet UIImageView *imageView;
#end
Implementation (nothing really impressive)
#import "class_3.h"
#interface class_3 ()
#end
#implementation class_3
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.imageView.image = [UIImage imageNamed:#"tempPhoto"];
}
#end
What am I missing?
Tnx

Your class_3 should be a UIView, instead of a UIViewController, subclass. See here

Related

When using JSQMessagesViewController as detailView in UISplitviewCOntroller, KeyBoardToolBar needs to appear in DetailViewController only

When using JSQMessagesViewController as detailView in UISplitViewController, KeyBoardToolBar needs to appear in DetailViewController only
late answer...
if u want to reduce the inputToolbar you need to create a subclass of JSQMessagesToolbarContentView and provide your own view for the tool bar's content view.
below i am giving the sample example, create a subcalss of JSQMessagesToolbarContentView name it as JSQMessagesToolbarContentView_custom in the subcalss add below code,
#import "JSQMessagesToolbarContentView.h"
#interface JSQMessagesToolbarContentView_custom : JSQMessagesToolbarContentView
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *holderViewLeadingConstraint;
#end
and in JSQMessagesToolbarContentView_custom.m file,
#import "UIView+JSQMessages.h"
#import "JSQMessagesToolbarContentView_custom.h"
#implementation JSQMessagesToolbarContentView_custom
+ (UINib *)nib
{
return [UINib nibWithNibName:NSStringFromClass([JSQMessagesToolbarContentView_custom class])
bundle:[NSBundle bundleForClass:[JSQMessagesToolbarContentView_custom class]]];
}
#pragma mark - Initialization
- (void)awakeFromNib
{
[super awakeFromNib];
[self setTranslatesAutoresizingMaskIntoConstraints:NO];
self.backgroundColor = [UIColor clearColor];
}
//below method will place the contentview to desired position
- (void)layoutSubviews
{
[super layoutSubviews];
self.holderViewLeadingConstraint.constant = 320;
}
#pragma mark - Setters
- (void)setBackgroundColor:(UIColor *)backgroundColor
{
[super setBackgroundColor:backgroundColor];
self.leftBarButtonContainerView.backgroundColor = backgroundColor;
self.rightBarButtonContainerView.backgroundColor = backgroundColor;
}
- (void)setLeftBarButtonItem:(UIButton *)leftBarButtonItem
{
[super setLeftBarButtonItem:leftBarButtonItem];
}
- (void)setLeftBarButtonItemWidth:(CGFloat)leftBarButtonItemWidth
{
// self.leftBarButtonContainerViewWidthConstraint.constant = leftBarButtonItemWidth;
[self setNeedsUpdateConstraints];
}
- (void)setRightBarButtonItem:(UIButton *)rightBarButtonItem
{
[super setRightBarButtonItem:rightBarButtonItem];
}
- (void)setRightBarButtonItemWidth:(CGFloat)rightBarButtonItemWidth
{
// self.rightBarButtonContainerViewWidthConstraint.constant = rightBarButtonItemWidth;
[self setNeedsUpdateConstraints];
}
- (void)setRightContentPadding:(CGFloat)rightContentPadding
{
// self.rightHorizontalSpacingConstraint.constant = rightContentPadding;
[self setNeedsUpdateConstraints];
}
- (void)setLeftContentPadding:(CGFloat)leftContentPadding
{
// self.leftHorizontalSpacingConstraint.constant = leftContentPadding;
[self setNeedsUpdateConstraints];
}
#pragma mark - UIView overrides
- (void)setNeedsDisplay
{
[super setNeedsDisplay];
[self.textView setNeedsDisplay];
}
//return the custom view that we are going to create next
- (JSQMessagesToolbarContentView_custom *)loadToolbarContentView
{
NSArray *nibViews = [[NSBundle bundleForClass:[JSQMessagesToolbarContentView_custom class]] loadNibNamed:NSStringFromClass([JSQMessagesToolbarContentView_custom class]) owner:nil options:nil];
return nibViews.firstObject;
}
after this you need to create add new .xib file name it as JSQMessagesToolbarContentView_custom.xib this file contains our small content view for the inputToolbar and more importantly set the out let connections as doing the demo example and aslo set the view class name to JSQMessagesToolbarContentView_custom. hear i can only add image of the custom view.
now create a outlet for leading constraint to reduce the size of the content view as give below,
and add the constraints outlet's as given in the demo. so if u add some constrians without modifying the base class it will give error or runtime error so edit the base class also
now go to JSQMessagesToolbarContentView.h and add the blow properties form JSQMessagesToolbarContentView.m just cut and past and make it public.
#interface JSQMessagesToolbarContentView : UIView
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *leftBarButtonContainerViewWidthConstraint;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *rightBarButtonContainerViewWidthConstraint;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *leftHorizontalSpacingConstraint;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *rightHorizontalSpacingConstraint;
//...rest of the code
now in the JSQMessagesInputToolbar.m file, in order to make the tool bar transperent for half of the splitview,
- (void)awakeFromNib
{
[super awakeFromNib];
//...rest of the code
[self setBackgroundImage:[UIImage new]//imageNamed:#"topbar"]
forToolbarPosition:UIToolbarPositionAny
barMetrics:UIBarMetricsDefault];
[self setShadowImage:[UIImage new] forToolbarPosition:UIBarPositionAny];
[self setBackgroundColor:[UIColor clearColor]];
}
thats it now run the project, and change the leading constraints constant you see below output,

How to place a PageControl in ScrollView having multiple images?

I have a scroll view which contain a view and view have five images in want a pagecontrol to show the navigation status but the page control hides behind the images. I tried everything searched internet but cant fined anything.
Implementation.h
#interface ScrollSecondViewController : UIViewController
{
IBOutlet UIView *scrContentSizeView;
IBOutlet UIScrollView * scrollView;
}
#property (nonatomic, weak) IBOutlet UIPageControl *pageControl;
#end
Implementation.m
- (void)viewDidLoad {
[super viewDidLoad];
[self.navigationItem setTitle:#"Scroll View"];
scrollView.contentSize = CGSizeMake(scrContentSizeView.frame.size.width, scrollView.frame.size.height);
scrollView.clipsToBounds = YES;
[scrollView setContentOffset:CGPointMake(750, 0) animated:YES];
// Do any additional setup after loading the view.
}
- (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
_pageControl.currentPage = scrollView.contentOffset.x / scrollView.frame.size.width;
}
In the viewDidLoad method you should add the following code as the last method you call after adding all subviews.
- (void)viewDidLoad {
[super viewDidLoad];
//do what u want
//this should be last
[self.view bringSubviewToFront:self.pageControl];
}

Multiple instance UIView only load xib file in the first instance

I'm working on as slideshow with some CustomUIView showed in a UIScrollView and it works good. But i have a custom UIView to show the content of each news. My slide works goods , but the XIB file of my custom view is loaded only for the first one and other customview are empty.
Here is my code :
my ViewController.m
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:YES];
int nbrNews = _sharedDataManager.rssfeeds.count;
_sliderView.contentSize = CGSizeMake(self.view.frame.size.width*nbrNews, self.view.frame.size.height);
self.pageControl.currentPage = 0;
self.pageControl.numberOfPages = nbrNews;
for (int i = 0; i< nbrNews; i++) {
NewsView *newsView = [[NewsView alloc] initWithFrame:CGRectMake(i*self.view.frame.size.width, 0, self.view.frame.size.width, self.view.frame.size.height)];
NSDictionary *news = [_sharedDataManager.rssfeeds objectAtIndex:i];
newsView.titleLabel.text = [news objectForKey:#"title"];
[_sliderView addSubview:newsView];
}
}
CustomView.h
#import <UIKit/UIKit.h>
#interface NewsView : UIView
#property (weak, nonatomic) IBOutlet UILabel *titleLabel;
#end
CustomView.m
#import "NewsView.h"
#implementation NewsView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self = [[[NSBundle mainBundle] loadNibNamed:#"OneNewsView" owner:self options:nil] objectAtIndex:0];
}
return self;
}
#end
here the result :
EDITED : i change the color of the view in my custom view. and we can see that only the first one is realy loaded with xib file. and i dont know why !!!! can you help me?
i solve my problem by adding :
self.frame = frame;
to my customView.m initWithFrame

View Delegate Not Being Called

I'm building a graphing app, and I have a view and a view controller, which acts as a delegate for the view (to retrieve information). While I haven't started the actual drawing yet, I am currently trying to store values in a dictionary; however, I have certain NSLogs placed methodically across the view controller and I noticed that the delegate methods I call from the view don't get called at all. For example, I call my scaleForGraph function, but it does not execute. Being new to this, I'm not sure if there's something I'm missing. FYI: I have no errors, it compiles and executes. I've tried to slim the code down as much as possible. Thank you for your help!
Here's the .h for my view, where I define the protocol:
// GraphView.h
#import <UIKit/UIKit.h>
#class GraphView;
#protocol GraphViewDelegate <NSObject>
- (float)scaleForGraph:(GraphView *)requestor;
-(NSMutableDictionary*) valuesForGraph:(GraphView *)requestor withWidth:(float) width;
#end
#interface GraphView : UIView
#property (nonatomic) id <GraphViewDelegate> delegate;
#property (nonatomic) id expressionCopy;
#end
And here's the .m:
#import "GraphView.h"
#implementation GraphView
#synthesize expressionCopy = _expressionCopy;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.contentMode = UIViewContentModeRedraw;
}
return self;
}
- (void)awakeFromNib
{
self.contentMode = UIViewContentModeRedraw;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
CGContextRef c = UIGraphicsGetCurrentContext();
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat width = screenSize.width;
CGFloat height = screenSize.height;
float scale = [self.delegate scaleForGraph:self];
NSLog([NSString stringWithFormat:#"My Scale: %f",scale]); //always returns 0
NSMutableDictionary *graphValues = [self.delegate valuesForGraph:self withWidth:width];
}
#end
And here's my view controller .h:
#import <UIKit/UIKit.h>
#import "GraphView.h"
#interface GraphingViewController : UIViewController <GraphViewDelegate>
#property (weak, nonatomic) IBOutlet GraphView *graphView;
#property (strong, nonatomic) IBOutlet UIStepper *stepper;
- (IBAction) changedScale:(UIStepper *)stepper;
#property (nonatomic) int scale;
#property (nonatomic) id expressionCopy;
#end
And here's the .m for the controller:
#import "GraphingViewController.h"
#interface GraphingViewController ()
#end
#implementation GraphingViewController
#synthesize expressionCopy = _expressionCopy;
- (void)updateUI
{
self.stepper.value = self.scale;
[self.graphView setNeedsDisplay];
}
- (void)setScale:(int)scale
{
if (scale < 0) scale = 0;
if (scale > 100) scale = 100;
_scale = scale;
[self updateUI];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)changedScale:(UIStepper *)stepper {
self.scale = stepper.value; //this function works fine, but is not delegate/does not get called by view
}
-(float) scaleForGraph:(GraphView *)requestor {
NSLog(#"HI"); //never gets here
}
-(NSMutableDictionary*) valuesForGraph:(GraphView *)requestor withWidth:(float) width {
NSLog(#"Hello2"); //never gets here
}
return xyVals;
}
#end
Nowhere in the code you've posted do you tell your GraphView that the GraphingViewController is it's delegate. So, you are sending a message to nil.
You'll want to do something like:
self.graphView.delegate = self;
In your GraphingViewController setup code.
Make your controller actual delegate of GraphView. You can do it in interface builder by Ctrl-dragging from GraphView to the object (orange circle in the bottom) and than choose "delegate"

MGSplitViewController not as RootView but within a UIViewController

I'm very new to iOS programming (Coming from Java / C++). I'm trying to set up an app with a TabBarController of which one tab should be a SplitView. I've done my research and I know that UISplitview will not work and everywhere people recommend using the MGSplitViewController. I've looked at the demo but I just can't figure out how to use it without it beeing the app's root view and can't find any sample code that could help
So here is what I do with the classes from the demo in a separate UIViewController class that I afterwards add to the TabBarController: This is my class:
#import <UIKit/UIKit.h>
#import "MGSplitCornersView.h"
#import "RootViewController.h"
#import "DetailViewController.h"
#interface ChannelViewController : UIViewController {
MGSplitViewController *splitViewController;
RootViewController *rootViewController;
DetailViewController *detailViewController;
}
#property (nonatomic, retain) MGSplitViewController *splitViewController;
#property (nonatomic, retain) RootViewController *rootViewController;
#property (nonatomic, retain) DetailViewController *detailViewController;
#end
And this is my desperate try to set it up
- (id)initWithTabBar
{
self = [super init];
//this is the label on the tab button itself
self.title = #"SplitView";
//use whatever image you want and add it to your project
//self.tabBarItem.image = [UIImage imageNamed:#"name_gray.png"];
// set the long name shown in the navigation bar at the top
self.navigationItem.title=#"Nav Title";
self.splitViewController = [[MGSplitViewController alloc] init];
self.rootViewController = [[RootViewController alloc] init];
self.detailViewController = [[DetailViewController alloc] init];
[self.splitViewController setDetailViewController:detailViewController];
[self.splitViewController setMasterViewController:rootViewController];
[self.view addSubview:splitViewController.view];
[self.rootViewController performSelector:#selector(selectFirstRow) withObject:nil afterDelay:0];
[self.detailViewController performSelector:#selector(configureView) withObject:nil afterDelay:0];
if (NO) { // whether to allow dragging the divider to move the split.
splitViewController.splitWidth = 15.0; // make it wide enough to actually drag!
splitViewController.allowsDraggingDivider = YES;
}
return self;
}
I guess I'm doing something wrong with delegates? Or do I have something else mixed up?
Is the demo doing things in the IB that I can't see in the code?
I get the split view but no content and especially no navigation bar with the buttons the demo comes with.
I'd be very thankful for hints or sample code!
Ok manny, here we go. This is my working code for the interface:
#import <UIKit/UIKit.h>
#import "MGSplitViewController.h"
#import "ecbView.h"
#import "ecbCalc.h"
#interface splitMain : MGSplitViewController <UIPopoverControllerDelegate,
MGSplitViewControllerDelegate>
{
IBOutlet UIPopoverController* popoverController;
IBOutlet UINavigationController* naviController;
IBOutlet ecbCalc* viewCalcLeft;
IBOutlet ecbView* euroRatesRight;
UIBarButtonItem* savedButtonItem;
BOOL keepMasterInPortraitMode;
BOOL memoryWasDropped;
BOOL viewLoaded;
}
#property (nonatomic, retain) UIPopoverController* popoverController;
#property (nonatomic, retain) UINavigationController* naviController;
#property (nonatomic, retain) ecbCalc* viewCalcLeft;
#property (nonatomic, retain) ecbView* euroRatesRight;
#property (nonatomic, retain) UIBarButtonItem* savedButtonItem;
#property (nonatomic, readonly) BOOL keepMasterInPortraitMode;
#property (nonatomic, readonly) BOOL memoryWasDropped;
#property (nonatomic, readonly) BOOL viewLoaded;
- (void)dismissPopoverController: (BOOL)animated;
- (void)settingsChanged;
#end
and here excerpts from implementation file:
- (id)initWithCoder:(NSCoder *)aDecoder
{
if ((self = [super initWithCoder:aDecoder]))
{
// my initialization...
}
return self;
}
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
CGRect rectFrame = CGRectMake(0.0, 20.0, 768.0, 1004.0 - 48.0); // being above a tab bar!
viewLoaded = NO;
self.view = [[UIView alloc] initWithFrame:rectFrame];
viewCalcLeft = [[ecbCalc alloc] initWithNibName:#"ecbCalc" bundle:nil];
euroRatesRight = [[ecbView alloc] initWithNibName:#"ecbView-iPad" bundle:nil];
naviController = [[UINavigationController alloc] initWithRootViewController:self.viewCalcLeft];
naviController.navigationBar.barStyle = UIBarStyleBlack;
naviController.title = nil;
viewCalcLeft.title = NSLocalizedString(#"BtnTitleCalc", #"");
viewCalcLeft.view.hidden = NO;
NSUserDefaults* prefs = [NSUserDefaults standardUserDefaults];
if ([prefs objectForKey:#"iPadAlwaysSplitTableView"] != nil)
self.keepMasterInPortraitMode = [prefs boolForKey:#"iPadAlwaysSplitTableView"];
else
self.keepMasterInPortraitMode = YES;
NSArray* theViewControllers = [NSArray arrayWithObjects:self.naviController, self.euroRatesRight, nil];
[self setViewControllers:theViewControllers];
[self setDelegate:self];
[self setShowsMasterInPortrait:keepMasterInPortraitMode];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
// protection because this one is called twice
if (viewLoaded)
return;
[super viewDidLoad];
if (memoryWasDropped)
{
if (!self.keepMasterInPortraitMode && UIInterfaceOrientationIsPortrait(self.interfaceOrientation))
{
// recreate popover controller
self.popoverController = [[UIPopoverController alloc] initWithContentViewController:self.viewCalcLeft];
}
}
viewLoaded = YES;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
memoryWasDropped = YES;
// Release any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
[self dismissPopoverController:NO];
self.popoverController = nil;
self.naviController = nil;
self.viewCalcLeft = nil;
self.euroRatesRight = nil;
viewLoaded = NO;
}
My MainWindow.xib has a UITabBarController and the button for splitMain is configured for this class but with an empty xib entry. So creation has to go via loadView. Maybe I could have done the viewDidLoad stuff within loadView ... but so I had to protect viewDidLoad from being called twice. That happens in loadView as soon as the view is instantiated from MGSplitViewController class because the initWithCoder there is calling [self setup]. In that function the frame rect is calculated with self.view.bounds so that viewDidLoad is called again because the view doesn't exist yet. Maybe one could implement a workaround within MGSplitViewController.m but I was too lazy doing that.
To get this working on a tab bar controller please make sure you commit most of the changes that are published on the MGSplitViewController's git page. Good luck.

Resources