Specified the scroll of a UIScrollView with an UIProgressView - objective-c

I would like to add a progress bar under the navigation bar which will indicate the progress of the scroll of a UIScrollView, I use (not work) : I do
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
self.progressView.progress = scrollView.contentOffset.y;
}

check now I created one demo:
#import "ViewController.h"
#interface ViewController ()<UIScrollViewDelegate>{
UIScrollView *scroll;
UIProgressView *indicater;
}
#end
#implementation ViewController
- (void)viewDidLoad {
indicater=[[UIProgressView alloc]initWithFrame:CGRectMake(0, 65, 320,10)];
indicater.backgroundColor=[UIColor redColor];
indicater.progress = 0.0;
indicater.hidden=false;
[self.view addSubview:indicater];
scroll=[[UIScrollView alloc]initWithFrame:CGRectMake(10, 80,300, 200)];
scroll.backgroundColor=[UIColor greenColor];
scroll.userInteractionEnabled=YES;
scroll.delegate=self;
scroll.contentSize = CGSizeMake(300 ,5000);
[self.view addSubview:scroll];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
CGPoint offset = scroll.contentOffset;
CGRect bounds = scroll.bounds;
CGSize size = scroll.contentSize;
UIEdgeInsets inset = scroll.contentInset;
float y = offset.y + bounds.size.height - inset.bottom;
float h = size.height;
NSLog(#"%f",y);
NSLog(#"%f",h);
NSNumber *num=[NSNumber numberWithFloat:y];
NSNumber *num1=[NSNumber numberWithFloat:h];
[self UpdateProgressbar:num TotalscrollLenrth:num1];
}
-(void)UpdateProgressbar:(NSNumber*)currentscrollLenrth TotalscrollLenrth:(NSNumber*)n
{
NSString *totalLength = [NSString stringWithFormat:#"%#", n];
NSLog(#"%#", totalLength);
NSString *currentScrool = [NSString stringWithFormat:#"%#", currentscrollLenrth];
NSLog(#"%#", currentScrool);
if (currentscrollLenrth <= n) {
[indicater setProgress:([currentScrool intValue]/[totalLength floatValue])];
}
else {
// do somithig
}
}

Related

Variables not updating while using CADisplayLink

I cannot get the variables to change when I update them. The method "reCenterYaw" fires when I touch the button and the variable "self.hasYawCenterPointBeenSet" gets updated within the method but when "updateCycle" method comes back around the variable is not showing it was updated. updateCycle is my CADisplaylink driven method. I've tried updating the variables to atomic, referenced them as their instance variables with "_" and with "self." Not sure what is going on.
#import "GameViewController.h"
#import <CoreMotion/CoreMotion.h>
#import <SpriteKit/SpriteKit.h>
#import "HUDOverlay.h"
#interface GameViewController ()
#property (strong, nonatomic) CMMotionManager *motionManager;
#property (strong, nonatomic) CMAttitude *currentAttitude;
#property (strong, nonatomic) SCNNode *cameraNode;
#property (strong, nonatomic) SCNScene *scene;
#property (nonatomic) float roll;
#property (nonatomic) float yaw;
#property (nonatomic) float pitch;
#property (atomic) float yawCenterPoint;
#property (atomic) BOOL hasYawCenterPointBeenSet;
#end
GameViewController* sharedGameViewController = nil;
#implementation GameViewController
+(GameViewController*)sharedController{
if (sharedGameViewController == nil) {
sharedGameViewController = [[GameViewController alloc] init];
}
return sharedGameViewController;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// create a new scene
//SCNScene *scene = [SCNScene sceneNamed:#"art.scnassets/ship.dae"];
_scene = [SCNScene new];
self.hasYawCenterPointBeenSet = NO;
// create and add a camera to the scene
_cameraNode = [SCNNode node];
_cameraNode.camera = [SCNCamera camera];
[_scene.rootNode addChildNode:_cameraNode];
// place the camera
_cameraNode.position = SCNVector3Make(0, 0, 0);
// create and add a light to the scene
SCNNode *lightNode = [SCNNode node];
lightNode.light = [SCNLight light];
lightNode.light.type = SCNLightTypeOmni;
lightNode.position = SCNVector3Make(0, 10, 10);
[_scene.rootNode addChildNode:lightNode];
// create and add an ambient light to the scene
SCNNode *ambientLightNode = [SCNNode node];
ambientLightNode.light = [SCNLight light];
ambientLightNode.light.type = SCNLightTypeAmbient;
ambientLightNode.light.color = [UIColor whiteColor];
[_scene.rootNode addChildNode:ambientLightNode];
// retrieve the SCNView
SCNView *scnView = (SCNView *)self.view;
scnView.delegate = self;
scnView.playing = YES;
// set the scene to the view
scnView.scene = _scene;
scnView.overlaySKScene = [HUDOverlay sceneWithSize:scnView.frame.size];
// allows the user to manipulate the camera
scnView.allowsCameraControl = NO;
// show statistics such as fps and timing information
scnView.showsStatistics = YES;
// configure the view
scnView.backgroundColor = [UIColor blueColor];
// // add a tap gesture recognizer
// UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
// NSMutableArray *gestureRecognizers = [NSMutableArray array];
// [gestureRecognizers addObject:tapGesture];
// [gestureRecognizers addObjectsFromArray:scnView.gestureRecognizers];
// scnView.gestureRecognizers = gestureRecognizers;
SCNNode *sampleNode = [SCNNode new];
SCNPlane *samplePlane = [SCNPlane planeWithWidth:3 height:5];
SCNMaterial *angryFrontMaterial = [SCNMaterial material];
angryFrontMaterial.diffuse.contents = [UIImage imageNamed:#"angryfront110.png"];
sampleNode.geometry = samplePlane;
sampleNode.geometry.firstMaterial = angryFrontMaterial;
sampleNode.position = SCNVector3Make(0, 0, -10);
[_scene.rootNode addChildNode:sampleNode];
// SCNAction *moveToCamera = [SCNAction moveTo:SCNVector3Make(0, 0, -10) duration:10];
// [sampleNode runAction:moveToCamera];
[self setupRotationGrid];
[self setupMotionCapture];
displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(updateCycle)];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
//This is the update loop for the sceneView. When the view updates per frame this is where the logic goes
-(void)renderer:(id<SCNSceneRenderer>)aRenderer updateAtTime:(NSTimeInterval)time{
}
-(void)updateCycle{
_currentAttitude = _motionManager.deviceMotion.attitude;
_roll = _currentAttitude.roll + (.5 * M_PI);
_yaw = _currentAttitude.yaw;
_pitch = _currentAttitude.pitch;
_cameraNode.eulerAngles = SCNVector3Make(-_roll, _yaw, _pitch);
//NSLog(#"yawCenterPoint = %d", _hasYawCenterPointBeenSet);
if (self.hasYawCenterPointBeenSet == NO) {
_yawCenterPoint = _yaw;
self.hasYawCenterPointBeenSet = YES;
NSLog(#"Yawcenter point set to %f", _yawCenterPoint);
}
//NSLog(#"Roll: %f Yaw: %f Pitch: %f", _roll, _yaw, _pitch);
}
-(void)setupRotationGrid {
double radius = 30;
double numberOfItems = 8;
SCNGeometry *geometry = [SCNBox boxWithWidth:4.5 height:8 length:3.25 chamferRadius:0.5];
double x = 0.0;
double z = radius;
double theta = (M_PI)/(numberOfItems/2);
double incrementalY = (M_PI)/(numberOfItems*2);
SCNNode *nodeCollection = [SCNNode node];
nodeCollection.position = SCNVector3Make(0, 4, 0);
for (int index = 1; index <= numberOfItems; index++) {
x = radius * sin(index*theta);
z = radius * cos(index*theta);
SCNNode *node = [SCNNode node];
node.geometry = geometry;
node.position = SCNVector3Make(x, 0, z);
float rotation = incrementalY * index;
node.rotation = SCNVector4Make(0, 1, 0, rotation);
[nodeCollection addChildNode:node];
}
[_scene.rootNode addChildNode:nodeCollection];
}
- (void) handleTap:(UIGestureRecognizer*)gestureRecognize
{
// retrieve the SCNView
SCNView *scnView = (SCNView *)self.view;
// check what nodes are tapped
CGPoint p = [gestureRecognize locationInView:scnView];
NSArray *hitResults = [scnView hitTest:p options:nil];
// check that we clicked on at least one object
if([hitResults count] > 0){
// retrieved the first clicked object
SCNHitTestResult *result = [hitResults objectAtIndex:0];
// get its material
SCNMaterial *material = result.node.geometry.firstMaterial;
// highlight it
[SCNTransaction begin];
[SCNTransaction setAnimationDuration:0.5];
// on completion - unhighlight
[SCNTransaction setCompletionBlock:^{
[SCNTransaction begin];
[SCNTransaction setAnimationDuration:0.5];
material.emission.contents = [UIColor blackColor];
[SCNTransaction commit];
}];
material.emission.contents = [UIColor redColor];
[SCNTransaction commit];
}
}
-(void)reCenterYaw{
self.hasYawCenterPointBeenSet = NO;
NSLog(#"Tapped recenter");
}
-(void)setupMotionCapture{
_motionManager = [[CMMotionManager alloc] init];
_motionManager.deviceMotionUpdateInterval = 1.0/60.0;
if (_motionManager.isDeviceMotionAvailable) {
[_motionManager startDeviceMotionUpdates];
_currentAttitude = _motionManager.deviceMotion.attitude;
}
// if (!_hasYawCenterPointBeenSet) {
// _yawCenterPoint = _currentAttitude.yaw;
// _hasYawCenterPointBeenSet = YES;
// }
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (BOOL)prefersStatusBarHidden {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return UIInterfaceOrientationMaskLandscape;
} else {
return UIInterfaceOrientationMaskAll;
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#end
I figured it out. I had created a singleton so that I could reference the view controller from the sprite kit hud class. The problem is that I load the view controller from the storyboard and then later, from the hud class init, I instantiate a new view controller because the "sharedViewController" never got initiated by the storyboard load. So, I just created a view controller property on the hud class and set it to self from the view controller did load code.

automatic UIScrollView with paging

I have a UIScrollView with paging enabled. However i want this scrollview to scroll right when a certain amount of time has passed. Is there a easy way to implement this or do i need to use a timer and programmatically scroll the scrollview?
Something like this website has in its header: http://denederlandsewateren.nl/ [notice the text "De Nederlandse Wateren" changes each x seconds]
You need a little method to help you scroll to the exact page, this is not implemented, but it's very simple, let's assume your scrollview is called myScrollview
This assumes you're scrolling horizontally, you can switch the code to fit your needs
-(void)scrollToPage:(NSInteger)aPage{
float myPageWidth = [myScrollView frame].size.width;
[myScrollView setContentOffset:CGPointMake(aPage*myPageWidth,y) animated:YES];
}
Then you setup a timer to call this method every 5 seconds for example, like this:
[[NSTimer scheduledTimerWithTimeInterval:5
target:self
selector:#selector(scrollPages)
userInfo:Nil
repeats:YES] fire];
Next step is to create the method that will be fired by the timer and scroll to the next page, I called it -(void)scrollPages, it also requires that you have two global variables called currentPage and numberOfPages, both are of type NSInteger
-(void)scrollPages{
[self scrollToPage:currentPage%numberOfPages];
currentPage++;
}
If something doesn't make sense let me know !
Found this on stackoverflow
[scrollView setContentOffset:CGPointMake(x, y) animated:YES];
To do slideshows with UIScrollView, you arrange all images in the scroll view, set up a repeated timer, then -setContentOffset:animated: when the timer fires.
In your .h file create outlets for scrollview and paging
#property (weak, nonatomic) IBOutlet UIScrollView *sliderScrollView;
#property (weak, nonatomic) IBOutlet UIPageControl *sliderPageControll;
#property (nonatomic,strong) NSArray *sliderImagesArray;
#property (nonatomic,strong) NSString *sliderIndexString;
#property (nonatomic,strong) NSString *currentPageIndexString;
after that in your .m file
[self.sliderScrollView setPagingEnabled:YES];
[self.sliderScrollView setBounces:NO];
[self.sliderScrollView setAlwaysBounceVertical:NO];
[self.sliderScrollView setShowsHorizontalScrollIndicator:NO];
self.sliderScrollView.alwaysBounceVertical = NO;
NSArray *imagesArray = self.sliderImagesArray;
for (int i = 0; i < [imagesArray count]; i++){
CGFloat xOrigin = i * self.imageSliderScrollView.frame.size.width;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(xOrigin, 0, self.sliderScrollView.frame.size.width, self.sliderScrollView.frame.size.height)];
imageView.userInteractionEnabled = YES;
NSString *imgStr = [serviceImgArray objectAtIndex:i];
NSString *bikeStr = [NSString stringWithFormat:#"%#", imgStr];
NSURL *imageURL = [NSURL URLWithString:[bikeStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
[imageView sd_setImageWithURL:imageURL
placeholderImage:[UIImage imageNamed:#"profilepic_bg"]];
[imageView setContentMode:UIViewContentModeScaleAspectFill];
[self.sliderScrollView addSubview:imageView];
}
// for adding autorotate scrolling
[NSTimer scheduledTimerWithTimeInterval:5 target:self selector:#selector(autoStartSlide:) userInfo:nil repeats:YES];
self.sliderPageControll.numberOfPages = imagesArray.count;
self.sliderPageControll.currentPage = 0;
self.currentPageIndexString = [NSString stringWithFormat:#"%ld",(long)0];
[self.sliderScrollView setContentSize:CGSizeMake(self.sliderScrollView.frame.size.width * [imagesArray count], self.sliderScrollView.frame.size.height)];
if ([self.sliderPageControll respondsToSelector:#selector(setPageIndicatorTintColor:)]) {
self.sliderPageControll.currentPageIndicatorTintColor = [UIColor redColor];
self.sliderPageControll.pageIndicatorTintColor = [UIColor whiteColor];
}
CGRect frame = self.sliderScrollView.frame;
frame.origin.x = frame.size.width * [[NSString stringWithFormat:#"%#",self.sliderIndexString] integerValue];
frame.origin.y = 0;
[self.sliderScrollView scrollRectToVisible:frame animated:NO];
self.sliderPageControll.currentPage = [[NSString stringWithFormat:#"%#",self.sliderIndexString] integerValue];
after that implement scrollview delegate method
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
NSInteger scrollIndex = (NSInteger)(self.sliderScrollView.contentOffset.x / self.sliderScrollView.frame.size.width);
self.sliderPageControll.currentPage = scrollIndex;
self.currentPageIndexString = [NSString stringWithFormat:#"%ld",(long)self.sliderPageControll.currentPage];
}
Here implement your autotrotate method.
- (void)autoStartSlide:(id)sender {
if(pagger.numberOfPages > pagger.currentPage+1) {
[UIView animateWithDuration:0.5 animations:^{
slider.contentOffset = CGPointMake(slider.contentOffset.x + slider.frame.size.width, 0);
} completion:^(BOOL finished) {
}];
}
else {
slider.contentOffset = CGPointMake(slider.contentOffset.x - slider.frame.size.width, 0);
[UIView animateWithDuration:0.5 animations:^{
slider.contentOffset = CGPointMake(slider.contentOffset.x + slider.frame.size.width, 0);
} completion:^(BOOL finished) {
slider.contentOffset = CGPointMake(0, 0) ;
}];
}
}
Here is a Swift 5 Compatible one
var currentPage = 1;
var slideTimer : Timer?
ViewDidLoad
slideTimer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(scrollPages), userInfo: nil, repeats: true)
viewDidDisappear
slideTimer?.invalidate()
Functions
#objc func scrollPages() {
scrollToPage(page: CGFloat(currentPage%slides.count));
currentPage+=1;
}
func scrollToPage(page : CGFloat) {
let pageWidth = scrollView.frame.width
scrollView .setContentOffset(CGPoint(x: pageWidth * page, y: 0.0), animated: true)
}

how to add lines in UITextView programmatically [duplicate]

I have a UITextView where the user can create notes and save into a plist file.
I want to be able to show lines just like a normal notebook. The problem I have is
that the text won't align properly.
The image below explains the problem quite well.
This is the background I use to create the lines like the Notes.app
This is my code for creating the background for my UITextView:
textView.font = [UIFont fontWithName:#"MarkerFelt-Thin" size:19.0];
textView.backgroundColor = [UIColor colorWithPatternImage: [UIImage imageNamed: #"Notes.png"]];
I know that the UIFont.lineHeight property is only available in > iOS 4.x.
So I wonder if there is another solution to my problem?
You should try and draw your lines programmatically rather than using an image. Here's some sample code of how you could accomplish that. You can subclass UITextView and override it's drawRect: method.
NoteView.h
#import <UIKit/UIKit.h>
#interface NoteView : UITextView <UITextViewDelegate> {
}
#end
NoteView.m
#import "NoteView.h"
#implementation NoteView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor colorWithRed:1.0f green:1.0f blue:0.6f alpha:1.0f];
self.font = [UIFont fontWithName:#"MarkerFelt-Thin" size:19];
}
return self;
}
- (void)drawRect:(CGRect)rect {
//Get the current drawing context
CGContextRef context = UIGraphicsGetCurrentContext();
//Set the line color and width
CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.2f].CGColor);
CGContextSetLineWidth(context, 1.0f);
//Start a new Path
CGContextBeginPath(context);
//Find the number of lines in our textView + add a bit more height to draw lines in the empty part of the view
NSUInteger numberOfLines = (self.contentSize.height + self.bounds.size.height) / self.font.leading;
//Set the line offset from the baseline. (I'm sure there's a concrete way to calculate this.)
CGFloat baselineOffset = 6.0f;
//iterate over numberOfLines and draw each line
for (int x = 0; x < numberOfLines; x++) {
//0.5f offset lines up line with pixel boundary
CGContextMoveToPoint(context, self.bounds.origin.x, self.font.leading*x + 0.5f + baselineOffset);
CGContextAddLineToPoint(context, self.bounds.size.width, self.font.leading*x + 0.5f + baselineOffset);
}
//Close our Path and Stroke (draw) it
CGContextClosePath(context);
CGContextStrokePath(context);
}
#end
MyViewController.h
#import <UIKit/UIKit.h>
#import "NoteView.h"
#interface MyViewController : UIViewController <UITextViewDelegate> {
NoteView *note;
}
#property (nonatomic, retain) NoteView *note;
#end
MyViewController.m
#import "MyViewController.h"
#import "NoteView.h"
#define KEYBOARD_HEIGHT 216
#implementation MyViewController
#synthesize note;
- (void)loadView {
[super loadView];
self.note = [[[NoteView alloc] initWithFrame:self.view.bounds] autorelease];
[self.view addSubview:note];
note.delegate = self;
note.text = #"This is the first line.\nThis is the second line.\nThis is the ... line.\nThis is the ... line.\nThis is the ... line.\nThis is the ... line.\nThis is the ... line.\n";
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
[note setNeedsDisplay];
}
- (void)textViewDidBeginEditing:(UITextView *)textView {
CGRect frame = self.view.bounds;
frame.size.height -= KEYBOARD_HEIGHT;
note.frame = frame;
}
- (void)textViewDidEndEditing:(UITextView *)textView {
note.frame = self.view.bounds;
}
- (void)dealloc {
[note release];
[super dealloc];
}
Take a look at Apple's documentation for Managing the Keyboard, specifically "Moving Content That Is Located Under the Keyboard". It explains how to listen for NSNotifcations and adjust your views properly.
I think the problem is with your image, the yellow space over the line is creating the problem.
You should edit the image.
And nice work.

Multiple images/buttons staying relative to their position on a zoomable image

I've made a map with UIScrolView, I want to place other small images or buttons onto the map and have them be in a relative position on the map when you zoom in and be able to click on them whenever. So when zoomed out, a button on country A, will still be on Country A when zoomed in, and disappear out of the screen when you scroll out of the countries view whilst zoomed in. How could I go about doing this?
As i can understand, you want to place custom views on your own custom map. And you need to keep the same sizes for views, but they should move when you scroll or zoom imageView.
You have to place views to scrollView's superview and recalculate positions when you zoom or scroll:
CustomMapViewController.h:
#interface CustomMapViewController : UIViewController <UIScrollViewDelegate>
{
UIScrollView *_scrollView;
UIImageView *_mapImageView;
NSArray *_customViews;
}
CustomMapViewController.m:
#import "CustomMapViewController.h"
enum {
kAddContactButton = 1,
kInfoDarkButton,
kInfoLightButton,
kLogoImage,
};
#implementation CustomMapViewController
- (void)dealloc
{
[_scrollView release]; _scrollView = nil;
[_mapImageView release]; _mapImageView = nil;
[_customViews release]; _customViews = nil;
[super dealloc];
}
- (void) loadView
{
[super loadView];
UIImageView *mapImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"map.png"]];
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
scrollView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
scrollView.delegate = self;
scrollView.minimumZoomScale = 0.2;
scrollView.maximumZoomScale = 2.0;
[scrollView addSubview:mapImageView];
scrollView.contentSize = mapImageView.frame.size;
[self.view addSubview:scrollView];
_scrollView = scrollView;
_mapImageView = mapImageView;
// Add custom views
UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeContactAdd];
btn1.tag = kAddContactButton;
[self.view addSubview:btn1];
UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeInfoDark];
btn2.tag = kInfoDarkButton;
[self.view addSubview:btn2];
UIButton *btn3 = [UIButton buttonWithType:UIButtonTypeInfoLight];
btn3.tag = kInfoLightButton;
[self.view addSubview:btn3];
UIImageView *image = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"logo.png"]] autorelease];
image.tag = kLogoImage;
[self.view addSubview:image];
_customViews = [[NSArray alloc] initWithObjects:btn1, btn2, btn3, image, nil];
[self _zoomToFit];
}
- (void) _zoomToFit
{
UIScrollView *scrollView = _scrollView;
CGFloat contentWidth = scrollView.contentSize.width;
CGFloat contentHeigth = scrollView.contentSize.height;
CGFloat viewWidth = scrollView.frame.size.width;
CGFloat viewHeight = scrollView.frame.size.height;
CGFloat width = viewWidth / contentWidth;
CGFloat heigth = viewHeight / contentHeigth;
CGFloat scale = MIN(width, heigth); // to fit
// CGFloat scale = MAX(width, heigth); // to fill
// May be should add something like this
if ( scale < _scrollView.minimumZoomScale ) {
_scrollView.minimumZoomScale = scale;
} else if ( scale > _scrollView.maximumZoomScale ) {
_scrollView.maximumZoomScale = scale;
}
_scrollView.zoomScale = scale;
}
////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Positions
- (void) _updatePositionForViews:(NSArray *)views
{
CGFloat scale = _scrollView.zoomScale;
CGPoint contentOffset = _scrollView.contentOffset;
for ( UIView *view in views ) {
CGPoint basePosition = [self _basePositionForView:view];
[self _updatePositionForView:view scale:scale basePosition:basePosition offset:contentOffset];
}
}
- (CGPoint) _basePositionForView:(UIView *)view
{
switch (view.tag) {
case kAddContactButton:
return CGPointMake(50.0, 50.0);
case kInfoDarkButton:
return CGPointMake(250.0, 250.0);
case kInfoLightButton:
return CGPointMake(450.0, 250.0);
case kLogoImage:
return CGPointMake(650.0, 450.0);
default:
return CGPointZero;
}
}
- (void) _updatePositionForView:(UIView *)view scale:(CGFloat)scale basePosition:(CGPoint)basePosition offset:(CGPoint)offset;
{
CGPoint position;
position.x = (basePosition.x * scale) - offset.x;
position.y = (basePosition.y * scale) - offset.y;
CGRect frame = view.frame;
frame.origin = position;
view.frame = frame;
}
//////////////////////////////////////////////////////////////////////////////////////
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidZoom:(UIScrollView *)scrollView
{
[self _updatePositionForViews:_customViews];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[self _updatePositionForViews:_customViews];
}
- (UIView *) viewForZoomingInScrollView:(UIScrollView *)scrollView;
{
return _mapImageView;
}
#end

iOS subview displayed as a black rectangle if drawRect is overwritten

I have a storyboard which loads loads a custom UIView. Also a sub view is added to the view in the storyboard. It worked fine until I overwrote the drawRect method of the sub view, then I just saw a black rectangle instead of the subview. Here is the code:
#import <UIKit/UIKit.h>
#import "MySubview.h"
#interface MyView : UIView
#end
#import "MyView.h"
#implementation MyView
- (void) awakeFromNib
{
CGRect frame = [self frame];
MySubview* sv = [[MySubview alloc] initWithFrame:frame];
[self addSubview:sv];
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
#end
#import <UIKit/UIKit.h>
#interface MySubview : UIView
#property (retain, nonatomic) NSString* text;
#property (retain, nonatomic) UILabel* label;
#end
#import "MySubview.h"
#implementation MySubview
#synthesize text, label;
- (void)attachLabel
{
text = #"Hello";
label = [[UILabel alloc] init];
[label setText:text];
[label setFont:[UIFont fontWithName:#"Futura" size:18]];
[label setBackgroundColor:[UIColor clearColor]];
[label sizeToFit];
CGRect labelFrame = label.frame;
labelFrame.origin.x = (self.frame.size.width - labelFrame.size.width) / 2;
labelFrame.origin.y = (self.frame.size.height - labelFrame.size.height) / 2;
label.frame = labelFrame;
[self addSubview:label];
}
- (void)awakeFromNib
{
[self attachLabel];
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self attachLabel];
}
return self;
}
// Works if I comment this out!
- (void)drawRect:(CGRect)rect
{
}
#end
Update - Added drawing code below:
- (void)drawRectWithRoundBorders:(CGRect)rect
{
[super drawRect:rect];
// Parameters used for drawing.
const CGFloat lineWidth = 5;
const CGFloat shadowOffset = 3;
const CGFloat shadowBlur = 4;
const CGFloat spaceToBB = 10; // Space to the bounding box of this view.
const CGFloat cornerRadii = 5;
const CGFloat lineColor[4] = { 0, 0, 0, 1 };
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(ctx, lineWidth);
CGContextSetStrokeColor(ctx, lineColor);
CGContextSetShadow(ctx, CGSizeMake(shadowOffset, shadowOffset), shadowBlur);
CGRect innerRect = rect;
innerRect.size.width -= 2*spaceToBB;
innerRect.size.height -= 2*spaceToBB;
innerRect.origin.x += spaceToBB;
innerRect.origin.y += spaceToBB;
UIBezierPath *path =
[UIBezierPath bezierPathWithRoundedRect:innerRect
byRoundingCorners:UIRectCornerAllCorners
cornerRadii:CGSizeMake(cornerRadii, cornerRadii)
];
CGContextAddPath(ctx, path.CGPath);
CGContextStrokePath(ctx);
}
- (void)drawRect:(CGRect)rect
{
[self drawRectWithRoundBorders:rect];
}
Update
It seems to work when I fill the bounding box of the sub view with some color first.
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGFloat white[] = {1, 1, 1, 0.5};
CGContextSetFillColor(ctx, white);
CGContextAddRect(ctx, rect);
CGContextFillPath(ctx);
Just add [self setOpaque:NO] in your initWithFrame: method.
That's because your drawRect is doing nothing. You override drawRect if you want to do custom drawing. So:
If you don't want to do custom drawing then don't override drawRect.
If you do want to do custom drawing then actually do something in drawRect.