So, I added a popupview to my uisliders. I got the code for the custom sliders with the popup from a guy who had already done that. The popup is showing, but the only problem is that the popup is showing inside the cell in which the slider is at, so it gets cut off at the end of the cell.
How can I bring the popupview in front of the cell ?
(I have multiple sliders each one in a different cell)
#import "MNEValueTrackingSlider.h"
#import "ToothTableViewController.h"
#pragma mark - Private UIView subclass rendering the popup showing slider value
#interface MNESliderValuePopupView : UIView {
MNEValueTrackingSlider *trackingSlider;
ToothTableViewController *toothViewController;
}
#property (nonatomic) float value;
#property (nonatomic, retain) UIFont *font;
#property (nonatomic, retain) NSString *text;
#end
#import "MNEValueTrackingSlider.h"
#import "ToothTableViewController.h"
#implementation MNESliderValuePopupView
#synthesize value=_value;
#synthesize font=_font;
#synthesize text = _text;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.font = [UIFont boldSystemFontOfSize:18];
}
return self;
}
- (void)dealloc {
self.text = nil;
self.font = nil;
[super dealloc];
}
- (void)drawRect:(CGRect)rect {
// Set the fill color
[[UIColor colorWithWhite:0 alpha:0.8] setFill];
// Create the path for the rounded rectanble
CGRect roundedRect = CGRectMake(self.bounds.origin.x , self.bounds.origin.y, self.bounds.size.width, self.bounds.size.height * 0.8);
UIBezierPath *roundedRectPath = [UIBezierPath bezierPathWithRoundedRect:roundedRect cornerRadius:6.0];
// Create the arrow path
UIBezierPath *arrowPath = [UIBezierPath bezierPath];
CGFloat midX = CGRectGetMidX(self.bounds);
CGPoint p0 = CGPointMake(midX, CGRectGetMaxY(self.bounds));
[arrowPath moveToPoint:p0];
[arrowPath addLineToPoint:CGPointMake((midX - 10.0), CGRectGetMaxY(roundedRect))];
[arrowPath addLineToPoint:CGPointMake((midX + 10.0), CGRectGetMaxY(roundedRect))];
[arrowPath closePath];
// Attach the arrow path to the buble
[roundedRectPath appendPath:arrowPath];
[roundedRectPath fill];
// Draw the text
if (self.text) {
[[UIColor colorWithWhite:1 alpha:0.8] set];
CGSize s = [_text sizeWithFont:self.font];
CGFloat yOffset = (roundedRect.size.height - s.height) / 2;
CGRect textRect = CGRectMake(roundedRect.origin.x, yOffset, roundedRect.size.width, s.height);
[_text drawInRect:textRect
withFont:self.font
lineBreakMode:UILineBreakModeWordWrap
alignment:UITextAlignmentCenter];
}
}
- (void)setValue:(float)aValue {
_value = aValue;
self.text = [NSString stringWithFormat:#"%4.2f", _value];
[self setNeedsDisplay];
}
#end
#pragma mark - MNEValueTrackingSlider implementations
#import "ToothTableViewController.h"
#implementation MNEValueTrackingSlider
#synthesize thumbRect;
#synthesize sliderButtonPoint;
#pragma mark - Private methods
- (void)_constructSlider {
valuePopupView = [[MNESliderValuePopupView alloc] initWithFrame:CGRectZero];
valuePopupView.backgroundColor = [UIColor clearColor];
valuePopupView.alpha = 0.0;
toothViewController = [[ToothTableViewController alloc] init];
[self addSubview:valuePopupView];
}
- (void)_fadePopupViewInAndOut:(BOOL)aFadeIn {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
if (aFadeIn) {
valuePopupView.alpha = 1.0;
} else {
valuePopupView.alpha = 0.0;
}
[UIView commitAnimations];
}
- (void)_positionAndUpdatePopupView {
CGRect _thumbRect = self.thumbRect;
CGRect popupRect = CGRectOffset(_thumbRect, 0, -(_thumbRect.size.height * 1.5));
valuePopupView.frame = CGRectInset(popupRect, -20, -10);
valuePopupView.value = (NSInteger)self.value;
}
#pragma mark - Memory management
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self _constructSlider];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self _constructSlider];
}
return self;
}
- (void)dealloc {
[valuePopupView release];
[super dealloc];
}
#pragma mark - UIControl touch event tracking
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
// Fade in and update the popup view
CGPoint touchPoint = [touch locationInView:self];
// Check if the knob is touched. Only in this case show the popup-view
if(CGRectContainsPoint(self.thumbRect, touchPoint)) {
[self _positionAndUpdatePopupView];
[self _fadePopupViewInAndOut:YES];
}
return [super beginTrackingWithTouch:touch withEvent:event];
}
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
// Update the popup view as slider knob is being moved
[self _positionAndUpdatePopupView];
return [super continueTrackingWithTouch:touch withEvent:event];
}
- (void)cancelTrackingWithEvent:(UIEvent *)event {
[super cancelTrackingWithEvent:event];
}
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
// Fade out the popoup view
[self _fadePopupViewInAndOut:NO];
[super endTrackingWithTouch:touch withEvent:event];
}
#pragma mark - Custom property accessors
- (CGRect)thumbRect {
CGRect trackRect = [self trackRectForBounds:self.bounds];
CGRect thumbR = [self thumbRectForBounds:self.bounds
trackRect:trackRect
value:self.value];
return thumbR;
}
#end
Ok so I gave up, I cant figure it out. That is the code for the slider and its popupview. If anyone feels like reading the whole thing I could use the help :P
You could try to add the popupview as a subview of the UITableView.
Then to move it along with the slider, you would have to calculate the point by getting the slider's position relative to your tableview.
This can be achieved by using the UIView's convertPoint:toView: method, for example:
CGPoint sliderButtonRelativePoint = [slider.superview convertPoint:sliderButtonPoint toView:tableView];
where slider.superview would be your UITableViewCell, sliderButtonPoint would be the middle-top point of the slider's round button (for example), and tableView would be, well... your UITableView.
You might have to play around with this a little, and you may find there are strange behaviours when scrolling the tableview, but that's what I would try first.
Related
Is that possible to give each pagination dots with different colors? Suppose if i have 4 dots means is that possible to give 4 different color for each dots in ios?
http://muthesblog.blogspot.in/2011/11/custompagecontrol.html
by using the above code in the blog you will get different color dots as shown below image with yellow rectangle.
For your convenience adding the code
implemetation of the custompagecontrol
PageControl *<pageControl> = [[[PageControl alloc] initWithFrame:f] autorelease];
<pageControl>.numberOfPages = 5;
<pageControl>.currentPage = 1;
<pageControl>.delegate = self;
[self.view addSubview:<pageControl>];
/// .h file
#import <UIKit/UIKit.h>
#protocol PageControlDelegate;
#interface PageControl : UIView {
#private
NSInteger _currentPage;
NSInteger _numberOfPages;
UIColor *dotColorCurrentPage;
UIColor *dotColorOtherPage;
NSObject<PageControlDelegate> *delegate;
}
// Set these to control the PageControl.
#property (nonatomic) NSInteger currentPage;
#property (nonatomic) NSInteger numberOfPages;
// Customize these as well as the backgroundColor property.
#property (nonatomic, retain) UIColor *dotColorCurrentPage;
#property (nonatomic, retain) UIColor *dotColorOtherPage;
// Optional delegate for callbacks when user taps a page dot.
#property (nonatomic, assign) NSObject<PageControlDelegate> *delegate;
#end
#protocol PageControlDelegate<NSObject>
#optional
- (void)pageControlPageDidChange:(PageControl *)pageControl;
#end
//.m file
#import "PageControl.h"
// Tweak these or make them dynamic.
#define kDotDiameter 10.0
#define kDotSpacer 7.0
#implementation PageControl
#synthesize dotColorCurrentPage;
#synthesize dotColorOtherPage;
#synthesize delegate;
- (NSInteger)currentPage{
return _currentPage;
}
- (void)setCurrentPage:(NSInteger)page{
_currentPage = MIN(MAX(0, page), _numberOfPages-1);
[self setNeedsDisplay];
}
- (NSInteger)numberOfPages{
return _numberOfPages;
}
- (void)setNumberOfPages:(NSInteger)pages{
_numberOfPages = MAX(0, pages);
_currentPage = MIN(MAX(0, _currentPage), _numberOfPages-1);
[self setNeedsDisplay];
}
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame]))
{
// Default colors.
self.backgroundColor = [UIColor clearColor];
self.dotColorCurrentPage = [UIColor greenColor];
self.dotColorOtherPage = [UIColor whiteColor];
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetAllowsAntialiasing(context, true);
CGRect currentBounds = self.bounds;
CGFloat dotsWidth = self.numberOfPages*kDotDiameter + MAX(0, self.numberOfPages-1)*kDotSpacer;
CGFloat x = CGRectGetMidX(currentBounds)-dotsWidth/2;
CGFloat y = CGRectGetMidY(currentBounds)-kDotDiameter/2;
for (int i=0; i<_numberOfPages; i++)
{
CGRect circleRect = CGRectMake(x, y, kDotDiameter, kDotDiameter);
if (i == _currentPage)
{
CGContextSetFillColorWithColor(context, self.dotColorCurrentPage.CGColor);
}
else
{
if(i==0) {
CGContextSetFillColorWithColor(context, [UIColor magentaColor].CGColor);
} else if(i==1) {
CGContextSetFillColorWithColor(context, [UIColor orangeColor].CGColor);
} else if (i==2) {
CGContextSetFillColorWithColor(context, [UIColor yellowColor].CGColor);
} else if (i==3) {
CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor);
} else if (i==4) {
CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);
}
}
CGContextFillEllipseInRect(context, circleRect);
x += kDotDiameter + kDotSpacer;
}
}
- (void)dealloc {
[dotColorCurrentPage release];
[dotColorOtherPage release];
[super dealloc];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!self.delegate) return;
CGPoint touchPoint = [[[event touchesForView:self] anyObject] locationInView:self];
CGFloat dotSpanX = self.numberOfPages*(kDotDiameter + kDotSpacer);
CGFloat dotSpanY = kDotDiameter + kDotSpacer;
CGRect currentBounds = self.bounds;
CGFloat x = touchPoint.x + dotSpanX/2 - CGRectGetMidX(currentBounds);
CGFloat y = touchPoint.y + dotSpanY/2 - CGRectGetMidY(currentBounds);
if ((x<0) || (x>dotSpanX) || (y<0) || (y>dotSpanY)) return;
self.currentPage = floor(x/(kDotDiameter+kDotSpacer));
if ([self.delegate respondsToSelector:#selector(pageControlPageDidChange:)])
{
[self.delegate pageControlPageDidChange:self];
}
}
#end
There is no native way to change the colour of each page indicator due to iOS restrictions.
You can however use the following code to change the colour of the currently selected indicator and that of the rest which might be a good compromise.
pageControl.pageIndicatorTintColor = [UIColor purpleColor];
pageControl.currentPageIndicatorTintColor = [UIColor magentaColor];
If this functionality is essential for your app I would advise creating a custom page indicator that serves your purpose or maybe find a library online that allows you to to do this.
I hope that answers your questions :)
Check this below code
pageControl.pageIndicatorTintColor = [UIColor purpleColor];
pageControl.currentPageIndicatorTintColor = [UIColor magentaColor];
or Please refer this link
http://stackoverflow.com/questions/2942636/how-can-i-change-the-color-of-pagination-dots-of-uipagecontrol
I'm trying to implement a simple color picker consisting of an image in a UIImageView. When the user drags a finger over it, I want an adjacent view to continuously update with the current pixel color.
I found what looks like something close to the ideal solution in #rdelmar's answer to this question on SO, so I borrowed the code and modified it to send the pickedColor back to a method on the AddCategoryViewController. This method (setColorview), however, is not updating the colorView.
My breakpoints and NSLogs are showing that the color information is being collected from the touch, sent and received, but apparently not applied, as indicated by the fact that the affected UIView colorView does not reflect the color. The most obvious issue is that the property colorView reads null, and I don't understand why.
As a bonus, I would really like for the picker to respond to a sliding finger, not just a tap.
I've included all the relevant code below, with important lines marked with //*******************
Thanks for looking! All help appreciated!
Code starts here, files are separated by ---------------------------:
//
// UIView+UIView_ColorOfPoint.m
// WMDGx
//
//
#import "UIView+UIView_ColorOfPoint.h"
#import <QuartzCore/QuartzCore.h>
#implementation UIView (UIView_ColorOfPoint)
-(UIColor *) colorOfPoint:(CGPoint)point
{
unsigned char pixel[4] = {0};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pixel,
1, 1, 8, 4, colorSpace, (CGBitmapInfo)kCGImageAlphaPremultipliedLast);
CGContextTranslateCTM(context, -point.x, -point.y);
[self.layer renderInContext:context];
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
UIColor *color = [UIColor colorWithRed:pixel[0]/255.0
green:pixel[1]/255.0 blue:pixel[2]/255.0
alpha:pixel[3]/255.0];
return color;
}
#end
-----------------------------------------
//
// ColorPickerView.m
// WMDGx
//
//
#import "ColorPickerView.h"
AddCategoryViewController *addCatVC;
#implementation ColorPickerView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint loc = [touch locationInView:self];
self.pickedColor = [self colorOfPoint:loc];
NSLog(#"Touches began");
//******************** For sending color info to setColorView in AddCategoryViewController
addCatVC = [[AddCategoryViewController alloc]init];
addCatVC.colorForColorView = self.pickedColor;
NSLog(#"Picked color is %#",self.pickedColor);
//******************** Call the method in AddCategoryViewController, which should display the color of the current pixel
[addCatVC setColorview];
}
#end
--------------------------------
//
// AddCategoryViewController.m
// WMDGx
//
//
#import "AddCategoryViewController.h"
#interface AddCategoryViewController ()
#end
#implementation AddCategoryViewController
NSMutableArray *array;
- (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.catTextField.delegate = self;
[self.pickerImageView setUserInteractionEnabled:YES];
self.colorView.layer.cornerRadius = 6;
// ********************I put this NSLog here to check the status of the property self.colorView
NSLog(#"Color view is %#",self.colorView);//_colorView UIView * 0x8a63d30 0x08a63d30 (from Variables View)
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[self.catTextField resignFirstResponder];
return YES;
}
-(void)setColorview // ********************This is where the backgroundColor of self.colorView should be set
{
NSLog(#"colorForColorView is %#",self.colorForColorView);
NSLog(#"Color view is %#",self.colorView); //_colorView UIView * nil 0x00000000 (from Variables View)
[self.colorView setBackgroundColor:self.colorForColorView]; //colorView should display the color, but doesn't
NSLog(#"Color view is %#",self.colorView); //_colorView UIView * nil 0x00000000 (from Variables View)
NSLog(#"Color view color is %#",self.colorView.backgroundColor);
}
- (IBAction)saveButton:(UIBarButtonItem *)sender
{
if (self.catTextField.text.length < 1)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No category created"
message:#"Please create a new category"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
else if (!self.colorView.backgroundColor)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No color selected"
message:#"Please select a color for your new category"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
else
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
self.thisCategory = [WMDGCategory MR_createInContext:localContext];
self.thisCategory.name = [self.catTextField.text uppercaseString];
self.thisCategory.color = self.colorView.backgroundColor;
[localContext MR_saveToPersistentStoreAndWait];
[self.thisCell setUserInteractionEnabled:NO];
[self.delegate addCatControllerDidSave];
}
}
- (IBAction)cancelButton:(UIBarButtonItem *)sender
{
[self.delegate addCatControllerDidCancel:self.thisCategory];
}
#end
Here is my code that I use for this purpose. In addition to touches began I have the same code for touches moved, and that allows the sliding effect that you also want. My adjacent view has a tag of 200 which I look up and set based on the selected color. It looks like your linked code is a bit cleaner than mine, but perhaps seeing this would be useful.
First, when I get touches:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouches = [event allTouches];
if ([allTouches count] != 1)
return;
UIView *picker = [self.view viewWithTag:100];
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
CGPoint p = [touch locationInView:self.view];
if (CGRectContainsPoint(picker.frame, p))
{
printf("Hit gradient!\n");
p = [touch locationInView:picker];
UIColor *c = [self getPixelColor:[UIImage imageNamed:#"gradient.png"]
xLoc:p.x
yLoc:p.y];
UIView *display = [self.view viewWithTag:200]; // representative color
[display setBackgroundColor:c];
}
}
The code for getting the color (I believe this code was adapted from other code on SO):
- (UIColor*)getPixelColor:(UIImage *)image xLoc:(int)x yLoc:(int)y
{
CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
const UInt8* data = CFDataGetBytePtr(pixelData);
if (x < 0 || x >= image.size.width || y < 0 || y >= image.size.height)
{
CFRelease(pixelData);
return [UIColor whiteColor];
}
int pixelInfo = ((image.size.width * y) + x ) * 4;
UInt8 red = data[pixelInfo];
UInt8 green = data[(pixelInfo + 1)];
UInt8 blue = data[pixelInfo + 2];
UInt8 alpha = data[pixelInfo + 3];
CFRelease(pixelData);
UIColor* color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];
return color;
}
I created a custom UIView to draw a "hole" ontop of a background
#implementation MaskWithHole
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.hole = CGRectZero;
self.holeColor = [UIColor clearColor];
}
return self;
}
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
return nil;
}
-(void)setHole:(CGRect)hole
{
_hole = hole;
[self setNeedsDisplay];
}
-(void)setHoleColor:(UIColor *)holeColor
{
_holeColor = holeColor;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
[self.backgroundColor setFill];
UIRectFill(rect);
// clear the background in the given rectangles
CGRect holeRect = self.hole;
CGRect holeRectIntersection = CGRectIntersection( holeRect, rect );
[self.holeColor setFill];
UIRectFill(holeRectIntersection);
}
#end
But the custom drawing is always the background color - disregarding the drawRect code
CGRect holeRect = self.hole;
CGRect holeRectIntersection = CGRectIntersection( holeRect, rect );
[self.holeColor setFill];
UIRectFill(holeRectIntersection);
when I change the color of the hole from clear to green i can see the green- so apperantly the method is drawing teh background on everything
The easy way to have a transparent hole in the middle of a solid background is using a png image of that size with transparency in the middle, and the solid color outside.
This seems to work
#interface MaskWithHole : UIView
// default cgrectzero
#property (nonatomic,assign) CGRect hole;
// default [uicolor clearcolor]
#property (nonatomic,strong) UIColor *holeColor;
#end
#interface MaskWithHole ()
#property (nonatomic,strong) UIColor *backGroundColorForMask;
#end
#implementation MaskWithHole
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.hole = CGRectZero;
self.holeColor = [UIColor clearColor];
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
}
return self;
}
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
return nil;
}
-(void)setHole:(CGRect)hole
{
_hole = hole;
[self setNeedsDisplay];
}
-(void)setHoleColor:(UIColor *)holeColor
{
_holeColor = holeColor;
[self setNeedsDisplay];
}
-(void)setBackgroundColor:(UIColor *)backgroundColor
{
[super setBackgroundColor:[UIColor clearColor]];
self.backGroundColorForMask = backgroundColor;
}
- (void)drawRect:(CGRect)rect
{
[self.backGroundColorForMask setFill];
UIRectFill(rect);
CGRect holeRectIntersection = CGRectIntersection( self.hole, rect );
[[UIColor clearColor] setFill];
UIRectFill(holeRectIntersection);
}
#end
I have three view controllers that are part of a UIScrollView. I want to be able to swipe between the three, although one of the view controllers has a UIPanGestureRecognizer. I use this pan gesture recognizer to allow the user to drag their finger up and down to increase and decrease the height of a rectangular UIView. Therefore, this UIPanGestureRecognizer only really needs to know about the upwards/downwards panning, and the scroll view can use the horizontal panning.
An example of this, is like the home screen; you can swipe left or right, but also swipe down to get spotlight. I want this kind of mechanism.
This is my code for the pan:
- (void)pan:(UIPanGestureRecognizer *)aPan; // When pan guesture is recognised
{
CGPoint location = [aPan locationInView:self.view]; // Location of finger on screen
CGRect secondRect = CGRectMake(210.0, 45.0, 70.0, 325.0); // Rectangles of maximimum bar area
CGRect minuteRect = CGRectMake(125.0, 45.0, 70.0, 325.0);
CGRect hourRect = CGRectMake(41.0, 45.0, 70.0, 325.0);
if (CGRectContainsPoint(secondRect, location)) { // If finger is inside the 'second' rectangle
CGPoint currentPoint = [aPan locationInView:self.view];
currentPoint.y -= 80; // Make sure animation doesn't go outside the bars' rectangle
if (currentPoint.y < 0) {
currentPoint.y = 0;
}
else if (currentPoint.y > 239) {
currentPoint.y = 239;
}
currentPoint.y = 239.0 - currentPoint.y;
CGFloat pointy = currentPoint.y - fmod(currentPoint.y, 4.0);
[UIView animateWithDuration:0.01f // Animate the bars to rise as the finger moves up and down
animations:^{
CGRect oldFrame = secondBar.frame;
secondBar.frame = CGRectMake(oldFrame.origin.x, (oldFrame.origin.y - (pointy - secondBar.frame.size.height)), oldFrame.size.width, (pointy));
}];
CGFloat result = secondBar.frame.size.height - fmod(secondBar.frame.size.height, 4.0);
secondInt = (result / 4.0); // Update labels with new time
self->secondLabel.text = [NSString stringWithFormat:#"%02d", secondInt];
}
The code is basically repeated for three separate rectangular UIViews.
If anyone can tell me how to get the homescreen-style panning/swiping into my app, that would be great!!
Alright, here is the short answer:
You have to use UIGestureRecognizer's method -requireGestureRecognizerToFail:.
And here is the long answer:
You have to make the pan gesture recognizer of your scroll view to succeed only if the pan gesture recognizer of TimerViewController fails. However that gesture (TimerViewController's gesture) should only succeed if the initial movement is vertical. If it is horizontal it should fail.
To accomplish this we have to subclass UIPanGestureRecognizer and modify it to fit those needs.
Here is what you have to do:
Disregard ALL the changes you made from my previous answer
Add VerticalPanGestureRecognizer to your project.
Modify TimerViewController as shown.
Modify ScrollViewController as shown.
VerticalPanGestureRecognizer.h
#import <UIKit/UIKit.h>
#import <UIKit/UIGestureRecognizerSubclass.h>
#interface VerticalPanGestureRecognizer : UIPanGestureRecognizer
#end
VerticalPanGestureRecognizer.m
#import "VerticalPanGestureRecognizer.h"
#interface VerticalPanGestureRecognizer ()
#property (nonatomic, assign) CGPoint origLoc;
#end
#implementation VerticalPanGestureRecognizer
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.origLoc = [[touches anyObject] locationInView:self.view.superview];
[super touchesBegan:touches withEvent:event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (self.state == UIGestureRecognizerStatePossible) {
CGPoint loc = [[touches anyObject] locationInView:self.view.superview];
CGFloat deltaX = fabs(loc.x - self.origLoc.x);
CGFloat deltaY = fabs(loc.y - self.origLoc.y);
if (deltaY < deltaX)
self.state = UIGestureRecognizerStateFailed;
}
[super touchesMoved:touches withEvent:event];
}
#end
TimerViewController.h
// Your imports here
#interface TimerViewController : UIViewController
{
// Your ivars here
}
// Add the following property
#property (nonatomic, strong) UIPanGestureRecognizer *pan;
// Your methods here
#end
TimerViewController.m
#import "TimerViewController.h"
#import "VerticalPanGestureRecognizer.h"
#implementation TimerViewController
#synthesize pan = _pan;
// prefersStatusBarHidden method here
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil // Initialise view controller
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Instantiate the pan gesture as "VerticalPanGestureRecognizer"
self.pan = [[VerticalPanGestureRecognizer alloc] initWithTarget:self action:#selector(pan:)]; // Create recogniser for a pan guesture
self.pan.maximumNumberOfTouches = self.pan.minimumNumberOfTouches = 1;
[self.view addGestureRecognizer:self.pan];
}
return self;
}
// The rest of your code here
#end
ScrollViewController.m
- (void)viewDidLoad
{
// Your code here
TimerViewController *tvc = [[TimerViewController alloc]init];
CGRect frame = tvc.view.frame;
frame.origin.x = 320;
tvc.view.frame = frame;
// Add the following line
[self.scrollView.panGestureRecognizer requireGestureRecognizerToFail:tvc.pan];
[self addChildViewController:tvc];
[self.scrollView addSubview:tvc.view];
[tvc didMoveToParentViewController:self];
// More code here
}
This new approach works perfectly. I tested it.
Let me know if you have more questions.
Cheers!
UPDATE
To answer the question you posted on the comments, here is what you have to do:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
BarsViewController *bvc = [[BarsViewController alloc]init];
[self addChildViewController:bvc];
[self.scrollView addSubview:bvc.view];
[bvc didMoveToParentViewController:self];
TimerViewController *tvc = [[TimerViewController alloc]init];
CGRect frame = tvc.view.frame;
frame.origin.x = 320;
tvc.view.frame = frame;
[self.scrollView.panGestureRecognizer requireGestureRecognizerToFail:tvc.pan];
[self addChildViewController:tvc];
[self.scrollView addSubview:tvc.view];
[tvc didMoveToParentViewController:self];
StopwatchViewController *svc = [[StopwatchViewController alloc] init];
frame = svc.view.frame;
frame.origin.x = 320*2;
svc.view.frame = frame;
[self addChildViewController:svc];
[self.scrollView addSubview:svc.view];
[svc didMoveToParentViewController:self];
self.scrollView.contentSize = CGSizeMake(320*3, self.view.frame.size.height);
self.scrollView.pagingEnabled = YES;
[self.scrollView setShowsHorizontalScrollIndicator:NO];
}
Again, I tested it and it's working. You just have to add the gesture recognizer for the bars
I wish to show the FBLoginView in a landscape Cocos2D layer. Originally with just having it added to the view it was thinking the view was portrait, but by adding
[loginview setTransform:CGAffineTransformMakeRotation(-M_PI / 2)];
I was able to have it rotate to landscape as I needed. Perfect. However, the problem arises when you click on it again to Log Out. The ActionSheet that appears is very warped and I can't press any buttons on it (see below).
http://www.dansinclair.co.uk/SO/FBLoginView_error.png
I also get an entry in my log when this happens;
Presenting action sheet clipped by its superview. Some controls might not respond to touches. On iPhone try -[UIActionSheet showFromTabBar:] or -[UIActionSheet showFromToolbar:] instead of -[UIActionSheet showInView:].
To my knowledge, it's not easy to customise the calls to and from the FBLoginView.
Any ideas/thoughts/advice would be great!
Ok, so I've found the solution.
Seeing as I'm using Cocos2D it was difficult (i.e. not standard) to use a UIKit element on the CCLayer. Thus, I had to implement CCUIViewWrapper and all is working fine.
Here's my code for CCUIViewWrapper to work with Cocos2D 2.X and ARC;
CCUIViewWrapper.h
#import "cocos2d.h"
#interface CCUIViewWrapper : CCSprite
{
UIView *uiItem;
float rotation;
}
#property (nonatomic, retain) UIView *uiItem;
+ (id) wrapperForUIView:(UIView*)ui;
- (id) initForUIView:(UIView*)ui;
- (void) updateUIViewTransform;
#end
CCUIViewWrapper.m
#import "CCUIViewWrapper.h"
#implementation CCUIViewWrapper
#synthesize uiItem;
+ (id) wrapperForUIView:(UIView*)ui
{
return [[self alloc] initForUIView:ui];
}
- (id) initForUIView:(UIView*)ui
{
if((self = [self init]))
{
self.uiItem = ui;
return self;
}
return nil;
}
-(void)setParent:(CCNode *)parent {
if(parent == nil) {
[uiItem removeFromSuperview];
} else if(uiItem != nil) {
[[[CCDirector sharedDirector] view] addSubview:uiItem];
}
[super setParent:parent];
}
-(void)updateUIViewTransform {
float thisAngle, pAngle;
CGAffineTransform transform = CGAffineTransformMakeTranslation(0, [[CCDirector sharedDirector] winSize].height);
for(CCNode *p = self; p != nil; p = p.parent) {
thisAngle = CC_DEGREES_TO_RADIANS(p.rotation);
if(p.ignoreAnchorPointForPosition)
transform = CGAffineTransformTranslate(transform, p.anchorPointInPoints.x, p.anchorPointInPoints.y);
if(p.parent != nil) {
pAngle = CC_DEGREES_TO_RADIANS(p.parent.rotation);
transform = CGAffineTransformTranslate(transform,
(p.position.x * cosf(pAngle))+(p.position.y * sinf(pAngle)),
(-p.position.y * cosf(pAngle))+(p.position.x * sinf(pAngle)));
}
else {
transform = CGAffineTransformTranslate(transform, p.position.x, -p.position.y);
}
transform = CGAffineTransformRotate(transform, thisAngle);
transform = CGAffineTransformScale(transform, p.scaleX, p.scaleY);
transform = CGAffineTransformTranslate(transform, -p.anchorPointInPoints.x, -p.anchorPointInPoints.y);
}
[uiItem setTransform:transform];
}
- (void) setVisible:(BOOL)v
{
[super setVisible:v];
[uiItem setHidden:!v];
}
- (void) setRotation:(float)protation
{
[super setRotation:protation];
[self updateUIViewTransform];
}
- (void) setScaleX:(float)sx
{
[super setScaleX:sx];
[self updateUIViewTransform];
}
- (void) setScaleY:(float)sy
{
[super setScaleY:sy];
[self updateUIViewTransform];
}
- (void) setOpacity:(GLubyte)opacity
{
[uiItem setAlpha:opacity/255.0];
[super setOpacity:opacity];
}
- (void) setContentSize:(CGSize)size
{
[super setContentSize:size];
uiItem.frame = CGRectMake(0, 0, self.contentSize.width, self.contentSize.height);
uiItem.bounds = CGRectMake(0, 0, self.contentSize.width, self.contentSize.height);
}
- (void) setAnchorPoint:(CGPoint)pnt
{
[super setAnchorPoint:pnt];
[self updateUIViewTransform];
}
- (void) setPosition:(CGPoint)pnt
{
[super setPosition:pnt];
[self updateUIViewTransform];
}
#end
I hope this helps someone else...