UIScrollview does not react to any touch? - ios

I am trying to do a simple scroll, but the views do not move after a touch, I am not sure why, the scrollview should handle the gesture, but something might be missing. Would someone know where?
Here is the code : I create a small horizontal scroll view, with some views inside. The views appear well, I am testing it on a device for the touch :
- (void)viewDidLoad {
[super viewDidLoad];
//horizontal scroll view
HorizScroll *ho = [[HorizScroll alloc] initWithFrame:CGRectMake(0, 0, 500, 100)];
for ( int i=0; i<3; i++){
MyView* mv = [[MyView alloc] init];
[ho addSubview:mv];
}
//ho.zoomScale = 0.3f;
[self.view addSubview:ho];
}
#implementation HorizScroll
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
}
return self;
}
-(void)addSubview:(UIView *)view{
[super addSubview:view];
NSUInteger numSubviews = self.subviews.count;
[view setFrame:CGRectMake(CGRectGetWidth(view.bounds)*(numSubviews),
0,
CGRectGetWidth(view.bounds),
CGRectGetHeight(view.bounds) )];
[self setContentSize:CGSizeMake(CGRectGetWidth(view.bounds)*(numSubviews),
CGRectGetHeight(view.bounds) )];
}
#implementation MyView
-(int)getRandomNumberBetween:(int)from to:(int)pto {
return (int)(from + arc4random() % (pto-from+1));
}
-(instancetype)init{
if ( self = [super init] ){
CGFloat red = [self getRandomNumberBetween:1 to:255];
self.backgroundColor = [UIColor colorWithRed:red/256.0
green:[self getRandomNumberBetween:1 to:255]/256.0
blue:[self getRandomNumberBetween:1 to:255]/256.0
alpha:1.0];
}
return self;
}
-(instancetype)initWithFrame:(CGRect)frame{
if ( self = [super initWithFrame:frame] ){
self.frame = CGRectMake(counterX, 0, 100, 100);
counterX += 50;
}
return self;
}

You need to set contentSize of scrollview to be larger than its frame size. so add this line after [self.view addSubview:ho].
ho.contentSize = CGSizeMake(501.f, 100.f);
or before [self.view addSubview:ho] and comment out the line:
[self setContentSize:CGSizeMake(CGRectGetWidth(view.bounds)*(numSubviews),
CGRectGetHeight(view.bounds))];
which is not necessary since you can set it after all subviews are added.

Related

initWithImage works fine initWithFrame is being called more than once

I am sublassing either an UIImageView or UIView for generating simple color tiles with digits. If I am using UIImageView, I use initWithImage method. If I use UIView, the method initWithFrame is being used.
Either red square image or programmatically generated red view is used for initialization.
The problem can be seen on two screenshots: when initWithImage is being used - everything works fine. If initWithFrame method is being used, I am ending with multiple white views without any information created in even order with normal views. All the screenshots and code attached.
This how it looks when initializing using initWithImage:
- (id)initWithImage:(UIImage *)image {
self = [super initWithImage:image];
if (self) {
//Some non-important, label-related stuff.
[self addSubview:self.numberLabel];
}
return self;
}
And this is how it looks with initWithFrame:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.redView = [self redViewWithFrame:frame];
[self addSubview:self.redView];
//label-related stuff
}
return self;
}
- (UIView *)redViewWithFrame:(CGRect)frame {
UIView *view = [[UIView alloc] initWithFrame:frame];
view.backgroundColor = [UIColor redColor];
view.alpha = 1;
return view;
}
And the for-loop, calling these initializers from another class (UIScrollView subclass). The label value is being set after the view had been initialized.
- (void)setNumberOfBlocks:(NSInteger)numberOfBlocks {
_blocks = [[NSMutableArray alloc] init];
CGSize contentSize;
contentSize.width = BLOCK_WIDTH * (numberOfBlocks);
contentSize.height = BLOCK_HEIGHT;
self.contentSize = contentSize;
for (int i = 0; i < numberOfBlocks; i++) {
CGFloat totalWidth = BLOCK_WIDTH * i;
CGRect frame = CGRectMake(0, 0, BLOCK_WIDTH, BLOCK_HEIGHT);
frame.origin.x = totalWidth;
BlockView *view = [[BlockView alloc] initWithImage:[UIImage imageNamed:#"block.png"]];
OR!!!
BlockView *view = [[BlockView alloc] initWithFrame:frame];
view.frame = frame;
NSString *number = [NSString stringWithFormat:#"%ld", (long)i + 1];
view.numberLabel.text = number;
[self addSubview:view];
[_blocks addObject:view];
}
}
Googling gave me the impression that this is very common problem, but I haven't found any solution how to beat this. Moreover, I still do not understand, why numbers are in totally right order, the only problem is view position.
The problem is that you're setting the frame of the red view to the superview's frame instead of its bounds. Since the red view is a subview of the BlockView, its frame needs to be relative to its superview, which you get with bounds (its not clear why you even need the red view, as opposed to setting the background color of the block view to red).
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.redView = [self redViewWithFrame:self.bounds];
[self addSubview:self.redView];
//label-related stuff
}
return self;
}
I think you should set the frame origin to (0,0) in redViewWithFrame in ordre to hâve superposed views

Displaying an alert view similar to UIAlertView

I am trying to create a custom "alert view", nothing too fancy I just want to display a view overtop of the current view just like a UIAlertView.
Now here is the problem...I made the view in a nib file and now I want to alloc/init the view whenever I need to present an alert.Can anyone help me?
This is my attempt to get the view initialized...as of right now this crashes my app when I alloc/init a new alert view.
The app is crashing by telling me the view is not key-value compliant for the outlets.. I definitely have the outlets hooked up properly, unless I have a "File's Owner" thing screwed up.
NSObject 0x14e49800> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key....
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self load];
}
return self;
}
- (void)load {
NSArray *views = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil];
[self addSubview:[views firstObject]];
}
- (void)awakeFromNib {
[super awakeFromNib];
}
- (id)initWithFrame:(CGRect)frame
{
self = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:nil options:nil][0];
if (self) {
[self addSubview:self.contentView];
self.frame = frame;
}
return self;
}
- (instancetype)initWithTitle:(NSString *)title
message:(NSString *)message
delegate:(id)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
confirmButtonTitle:(NSString *)confirmButtonTitle {
self = [self initWithFrame:CGRectMake(0, 0, 320, 568)];
if (self) {
}
return self;
}
I made this method to present the view, just a simple addSubview...
- (void)showInView:(UIView *)view {
[view addSubview:self];
}
Try disabling autolayout and run the code.
Create a class same as below
#import "MyOverLay.h"
#interface MyOverLay (){
// control declarations
UIActivityIndicatorView *activitySpinner;
UILabel *loadingLabel;
}
#end
#implementation AcuOverLay
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
- (void)show:(NSString *)message{
// configurable bits
self.backgroundColor = [UIColor blackColor];
self.alpha = 0.75f;
self.autoresizingMask =UIViewAutoresizingFlexibleHeight;
float labelHeight = 22;
float labelWidth = self.frame.size.width - 20;
// derive the center x and y
float centerX = self.frame.size.width / 2;
float centerY = self.frame.size.height / 2;
// create the activity spinner, center it horizontall and put it 5 points above center x
activitySpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activitySpinner.frame = CGRectMake(centerX - (activitySpinner.frame.size.width / 2) , centerY - activitySpinner.frame.size.height - 20, activitySpinner.frame.size.width, activitySpinner.frame.size.height);
activitySpinner.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[self addSubview:activitySpinner];
[activitySpinner startAnimating];
// create and configure the "Loading Data" label
loadingLabel = [[UILabel alloc]initWithFrame:CGRectMake(centerX - (labelWidth / 2), centerY + 20 , labelWidth, labelHeight)];
loadingLabel.backgroundColor = [UIColor clearColor];
loadingLabel.textColor = [UIColor whiteColor];
loadingLabel.text = message;
loadingLabel.textAlignment = NSTextAlignmentCenter;
loadingLabel.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[self addSubview:loadingLabel];
}
- (void)hide{
[UIView animateWithDuration:0.5 animations:^{
self.alpha = 0;
[self removeFromSuperview];
}];
}
#end
then create instance wherever you want
loadingOverlay = [[MyOverLay alloc]initWithFrame:[UIScreen mainScreen].bounds];
loadingOverlay.tag = 999;
[[[UIApplication sharedApplication] keyWindow] addSubview:loadingOverlay];
[loadingOverlay show:#"Saving ..."];

How to pinch zoom multiple UIImageViews inside UIScrollView

I have to pinch zoom multiple images. I have added each of the UIImageView to UIView and added the UIView to UIScrollView. and returning the UIView image viewForZoomingInScrollView: delegate method, but images are not zooming as expected. is there any better way?
#define VIEW_FOR_ZOOM_TAG (1)
#implementation [SVViewController][1]
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView *mainScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
mainScrollView.pagingEnabled = YES;
mainScrollView.showsHorizontalScrollIndicator = NO;
mainScrollView.showsVerticalScrollIndicator = NO;
CGRect innerScrollFrame = mainScrollView.bounds;
for (NSInteger i = 0; i < 3; i++) {
UIImageView *imageForZooming = [[UIImageView alloc] initWithImage:[UIImage imageNamed:
[NSString stringWithFormat:#"page%d", i + 1]]];
imageForZooming.tag = VIEW_FOR_ZOOM_TAG;
UIScrollView *pageScrollView = [[UIScrollView alloc] initWithFrame:innerScrollFrame];
pageScrollView.minimumZoomScale = 1.0f;
pageScrollView.maximumZoomScale = 2.0f;
pageScrollView.zoomScale = 1.0f;
pageScrollView.contentSize = imageForZooming.bounds.size;
pageScrollView.delegate = self;
pageScrollView.showsHorizontalScrollIndicator = NO;
pageScrollView.showsVerticalScrollIndicator = NO;
[pageScrollView addSubview:imageForZooming];
[mainScrollView addSubview:pageScrollView];
if (i < 2) {
innerScrollFrame.origin.x += innerScrollFrame.size.width;
}
}
mainScrollView.contentSize = CGSizeMake(innerScrollFrame.origin.x +
innerScrollFrame.size.width, mainScrollView.bounds.size.height);
[self.view addSubview:mainScrollView];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return [scrollView viewWithTag:VIEW_FOR_ZOOM_TAG];
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
- (BOOL)shouldAutorotate {
return NO;
}
#end
[1]: http://www.lyricspoints.com
Check the minimum and maximum zoom scale properties of the scroll view. (max should be greater than min for zoom to happen)
make sure that you are returning the corresponding UIImageView and not the UIView
Make sure that you have set the scroll view delegate as the object to which you want the delegate messages of the scroll view to be sent, like viewForZoomingInScrollView:

self.view.size in a custom view returns [0,0]

I have my custom view:
#interface MailAttributesView : UIView
{
...
#implementation MailAttributesView
{
UIView *_selectionView;
}
(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
DLog(#"frame.size.width -[%f]; frame.size.height -[%f] ",frame.size.width, frame.size.height);
}
return self;
}
-(void)awakeFromNib
{
[self initView];
}
-(void)initView
{
DLog(#"self.frame.size.width -[%f]; self.frame.size.height -[%f] ",self.frame.size.width, self.frame.size.height);
CGRect sectionSize = CGRectMake(0, 0 , self.frame.size.width, self.frame.size.height);
_selectionView = [[UIView alloc] initWithFrame:sectionSize];
[_selectionView setBackgroundColor:[UIColor clearColor]];
fromField = [[JSTokenField alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, ROW_HEIGHT)];
[[fromField label] setText:#" From:"];
[fromField setDelegate:self];
[_selectionView addSubview:fromField];
In my storyboard I've created a view and set it my custom view class. Problem that in my view I call self.view to define width of the view - but it always returns 0.
I can hardcore needed values - but I expect to get it working like standard controls work - I mean for example auto-sizing if rotate and so on.
What's my misunderstanding?
If you are adding the custom view in storyboards, you would not be using initWithFrame:
Instead use initWithCoder:
Try this:
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
DLog(#"self.frame.size.width -[%f]; self.frame.size.height -[%f] ",self.frame.size.width, self.frame.size.height);
}
return self;
}

Programmatically Linking UIPageControl to UIScrollView

I am making a simple slideshow view within my app. I'd like to link my UIPageControl to my UIScrollView. This shouldn't be too difficult, but I haven't been able to find a simple solution anywhere. Below is my code.
HelpViewController.h
#import <UIKit/UIKit.h>
#interface HelpViewController : UIViewController{
}
#end
HelpViewController.m
#import "HelpViewController.h"
#interface HelpViewController ()
#end
#implementation HelpViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect scrollViewFrame = CGRectMake(0, 62, 320, 404);
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:scrollViewFrame];
[self.view addSubview:scrollView];
CGSize scrollViewContentSize = CGSizeMake(640, 404);
[scrollView setContentSize:scrollViewContentSize];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(200, 200, 50, 21)];
[label setText:#"Hello"];
[scrollView addSubview:label];
[scrollView setPagingEnabled:YES];
scrollView.showsHorizontalScrollIndicator = NO;
UIPageControl *pageControl = [[UIPageControl alloc] init];
pageControl.frame = CGRectMake(110,5,100,100);
pageControl.numberOfPages = 2;
pageControl.currentPage = 0;
[self.view addSubview:pageControl];
pageControl.backgroundColor = [UIColor redColor];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
Maybe this works for you
Don't forget to set the UIScrollView's delegate = self (or wherever you have the selector below).
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat pageWidth = self.scrollView.frame.size.width; // you need to have a **iVar** with getter for scrollView
float fractionalPage = self.scrollView.contentOffset.x / pageWidth;
NSInteger page = lround(fractionalPage);
self.pageControl.currentPage = page; // you need to have a **iVar** with getter for pageControl
}
For your code it then would be:
.h file
#import <UIKit/UIKit.h>
#interface HelpViewController : UIViewController{
}
#property (nonatomic, retain) UIScrollView *scrollView;
#property (nonatomic, retain) UIPageControl * pageControl;
#end
.m file
#import "HelpViewController.h"
#interface HelpViewController ()
#end
#implementation HelpViewController
#synthesize scrollView=scrollView_;
#synthesize pageControl=pageControl_;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect scrollViewFrame = CGRectMake(0, 62, 320, 404);
self.scrollView = [[[UIScrollView alloc] initWithFrame:scrollViewFrame] autorelease];
self.scrollView.delegate = self;
[self.view addSubview:self.scrollView];
CGSize scrollViewContentSize = CGSizeMake(640, 404);
[self.scrollView setContentSize:scrollViewContentSize];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(200, 200, 50, 21)];
[label setText:#"Hello"];
[self.scrollView addSubview:label];
[self.scrollView setPagingEnabled:YES];
self.scrollView.showsHorizontalScrollIndicator = NO;
self.pageControl = [[[UIPageControl alloc] init] autorelease];
self.pageControl.frame = CGRectMake(110,5,100,100);
self.pageControl.numberOfPages = 2;
self.pageControl.currentPage = 0;
[self.view addSubview:self.pageControl];
pageControl.backgroundColor = [UIColor redColor];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat pageWidth = self.scrollView.frame.size.width;
float fractionalPage = self.scrollView.contentOffset.x / pageWidth;
NSInteger page = lround(fractionalPage);
self.pageControl.currentPage = page;
}
#end
This is actually quite simple to setup. Firstly you need to create the scroll view and page control. Make sure you implement UIScrollViewDelegate in the interface of the class.
UIScrollView * scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * 3, scrollView.frame.size.height);
scrollView.delegate = self;
UIPageControl * pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 90, scrollView.frame.size.width, 20)];
pageControl.numberOfPages = scrollView.contentSize.width/scrollView.frame.size.width;
[pageControl addTarget:self action:#selector(changePage:) forControlEvents:UIControlEventValueChanged];
Then you need to add the following two methods:
- (IBAction)changePage:(id)sender {
CGFloat x = pageControl.currentPage * scrollView.frame.size.width;
[scrollView setContentOffset:CGPointMake(x, 0) animated:YES];
}
-(void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
NSInteger pageNumber = roundf(scrollView.contentOffset.x / (scrollView.frame.size.width));
pageControl.currentPage = pageNumber;
}
These methods add the required communication between the page control and the scroll view.
Following code will work for Swift:
func addScrollView() {
let scrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
let numberOfPages: CGFloat = 4
scrollView.contentSize = CGSize(width: scrollView.frame.width * numberOfPages, height: scrollView.frame.height * numberOfPages)
scrollView.delegate = self
scrollView.isPagingEnabled = true
let pageControl = UIPageControl(frame: CGRect(x: 0, y: scrollView.frame.height - 37, width: scrollView.frame.width, height: 37))
pageControl.numberOfPages = Int(numberOfPages)
pageControl.currentPage = 0
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let value = scrollView.contentOffset.x / scrollView.frame.size.width
pageControl.currentPage = Int(round(value))
}
to get exact page index without rounding off the value simply put the pagecontrol.currentpage in the scrollViewDidEndDecelerating delegate method of scroll view.This works for me!
All these answers are great but I'd like to offer an alternative solution, using ReactiveCocoa!
The following code makes an assumption that you have a property called scrollView and one called pageControl.
[RACObserve(self.scrollView, contentOffset)
subscribeNext:^(NSValue* value){
CGPoint offset = [value CGPointValue];
CGFloat fractional = offset.x/self.scrollView.width;
[self.pageControl setCurrentPage:lroundf(fractional)];
}];
All that's going on here is you're observing change on the contentOffset property of the scrollView and calculating the page index on every next event (i.e. every time the property value changes).
The only downside of this is that you have to unbox the CGPoint but on the upside there's no UIScrollViewDelegate code needed at all!

Resources