How to always rotate half with facebook POP? - ios

I'm new in iOS.
I want to always rotate half when user clicked a button.
Following is the code, it only rotate once and never rotate again when I clicked it.
#property UIButton *button;
- (void)viewDidLoad {
[super viewDidLoad];
CGFloat buttonSize = 220;
self.button = [UIButton buttonWithType:UIButtonTypeCustom];
self.button.backgroundColor = [UIColor colorFromHexString:#"#B084C7"];
self.button.frame = CGRectMake(0, 0, buttonSize, buttonSize);
[self.button addTarget:self
action:#selector(didTap:)
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.button];
}
- (void)didTap:(id)sender {
POPSpringAnimation *anim = [self.button.layer pop_animationForKey:#"rotate"];
if (anim) {
anim.toValue = #(M_PI * 0.5);
} else {
anim = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerRotation];
anim.toValue = #(M_PI * 0.5);
anim.springSpeed = 3;
anim.springBounciness = 1;
}
[self.button.layer pop_addAnimation:anim forKey:#"rotate"];
}

You are always rotating to the same value #(M_PI * 0.5) this is an absolute rotation that is applied to the layer. If you want to increment the angle then you need to do something like this:
anim.toValue = #(anim.fromValue.floatValue + (M_PI * 0.5));

Related

should this CustomView be a category or a subclass?

I want to extend an existing custom UIViewclass so it can be used in several places within an app. The view has a method that arranges multiple UIButtonsin a circle. The number of UIButtons will vary depending on where the method is called. So too will the size of the UIButton and the radius of the circle. It would also be useful (but not essential) to be able to call the method several times within the same UIView.
Which is the better way ? to make this a category or a sub-class? It would appear I could use either based on this discussion of pros and cons. But my question is more specific.
I’ve made categories for UIColor and UIFontbut so far I have not been able to make this method work as a category just by following Apple's documentation (I tried it both as a class method and as an instance method). Before I try to make it work as a subclass, can someone who has done it before, either way, please recommend the better approach based on my example below.
Here is the method as it was in the CustomView
circleOfButtons
- (void)circleOfButtons {
screenCentre.x = CGRectGetWidth (self.bounds) / 2;
screenCentre.y = CGRectGetHeight (self.bounds) / 2;
for (int i = 1; i <= buttonCount; i++) {
radians = 2 * M_PI * i / buttonCount;
CGFloat arcStartPoint = - M_PI / 2; // first point clockwise after 12 o'clock
buttonCentre.x = screenCentre.x + radius * cos(radians + arcStartPoint);
buttonCentre.y = screenCentre.y + radius * sin(radians + arcStartPoint);
CGPoint target = CGPointMake(buttonCentre.x, buttonCentre.y);
CGFloat x = screenCentre.x - buttonSize / 2;
CGFloat y = screenCentre.y - buttonSize / 2;
CGFloat wide = buttonSize;
CGFloat high = buttonSize;
UIButton *circleButton = [[UIButton alloc] initWithFrame:CGRectMake(x, y, wide, high)];
[circleButton setTag:i];
circleButton.clipsToBounds = YES;
circleButton.layer.masksToBounds = NO;
circleButton.layer.borderWidth = 0.25f;
circleButton.layer.cornerRadius = buttonSize/2;
circleButton.layer.borderColor = [UIColor blackColor].CGColor;
circleButton.backgroundColor = UIColor.whiteColor;
[circleButton setTitle:[NSString stringWithFormat:#"%i", i] forState:UIControlStateNormal];
[self addSubview:circleButton];
// animation 1
[UIView animateWithDuration:0.5 animations:^{
circleButton.transform = CGAffineTransformMakeScale(1.0, 1.0);
circleButton.center = screenCentre;
}
completion:^(BOOL finished){}];
// animation 2
[UIView animateWithDuration:1.0f animations:^{
circleButton.transform = CGAffineTransformIdentity;
circleButton.center = target;
}
completion:^(BOOL finished){}];
}
and here is the CustomView
CustomView.m
#import <UIKit/UIKit.h>
#import "CustomView.h"
#implementation CustomView : UIView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:[UIScreen mainScreen].bounds];
if (self) {
self.translatesAutoresizingMaskIntoConstraints = true;
self.backgroundColor = [UIColor lightGrayColor];
buttonCount = 5; //16;
buttonSize = 80; //41;
radius = 68; //105;
[self circleOfButtons];
}
return self;
}
CustomView.h
#import <UIKit/UIKit.h>
#interface CustomView : UIView {
CGPoint screenCentre, buttonCentre;
float radius, radians, buttonSize;
int buttonCount;
}
ViewController.m
#import "ViewController.h"
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CGRect rect = [UIScreen mainScreen].bounds;
float statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
CGRect screenFrame = CGRectMake(0, statusBarHeight, rect.size.width, rect.size.height - statusBarHeight);
self.view = [[UIView alloc] initWithFrame: screenFrame];
CustomView *cv = [[CustomView alloc]initWithFrame:screenFrame];
[self.view addSubview:cv];
}

iOS, create custom popover style UIView

I know there is alot of documentation on this topic, and from what i've read i've learned a lot. My issue here is that i began creating a custom UIView within a viewcontroller & now when i'm trying to make it the UIView its own class, so as to be called & used within a working app, i'm pretty confused as to what i need to do to achieve it.
The overall aim of the class is to be able to select a button one a view controller, which will instantiate the custom view, then display. The visual effect for the user is that they click the button, then a window will animate-appear from the bounds of the button (although the code below uses the positioning of top left currently), then display a combination of switches & labels, along with a back & save button.
You can see from my code that what i need to achieve this process, i've managed to implement into a single function (again, this was from creating it within a viewcontroller). What i'm after now, and can't quite fathom out is for the custom view to be imported, then on the action of the main view controller's button, add the view to self.view.
- (void)makeBox{
//view bounds
CGFloat viewWidth = CGRectGetWidth(self.view.frame);
CGFloat viewHeight = CGRectGetHeight(self.view.frame);
//red box x, y & size
CGFloat startx = (viewWidth / 100) * 10;
CGFloat starty = (viewHeight /100) * 20;
CGFloat width = (viewWidth / 100) * 80;
CGFloat height = (viewHeight /100) * 70;
CGRect view1Frame = CGRectMake(startx, starty, width, height);
//label & switch frame
CGRect labelMR = CGRectMake(10, ((height / 100) * 12), ((width / 100) * 80) - 7.5, 25);
CGRect switchMR = CGRectMake(((width / 100) * 80) + 7.5, ((height / 100) * 11), ((width / 100) * 10), 15);
//this is repeated for 6 other labels & switches
CGRect backButtonR = CGRectMake(5, 5, 50, 35);
CGRect saveButtonR = CGRectMake((width - 50), 5, 50, 35);
if (!self.view1) {
self.switchM = [[UISwitch alloc] initWithFrame:switchMR];
self.switchM.tag = 10;
if(self.monday){ //self.monday refers to a BOOL property of the viewcontroller that this was originally made in
self.switchM.on = true;
} else{
self.switchM.on = false;
}
[self.switchM addTarget:self action:#selector(switched:) forControlEvents:UIControlEventTouchUpInside];
// this switch instantiation process is repeated 6 other times
self.backButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[self.backButton addTarget:self
action:#selector(hideBox)
forControlEvents:UIControlEventTouchUpInside];
[self.backButton setTitle:#"Back" forState:UIControlStateNormal];
self.backButton.frame = backButtonR;
self.saveButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[self.saveButton addTarget:self
action:#selector(daysChanged)
forControlEvents:UIControlEventTouchUpInside];
[self.saveButton setTitle:#"Save" forState:UIControlStateNormal];
self.saveButton.frame = saveButtonR;
self.labelM = [[UILabel alloc] initWithFrame:labelMR];
self.labelM.layer.masksToBounds = YES;
self.labelM.layer.cornerRadius = 5;
self.labelM.layer.borderColor = [UIColor blackColor].CGColor;
self.labelM.layer.borderWidth = .5;
self.labelM.text = #" Monday";
self.labelM.backgroundColor = [UIColor whiteColor];
//again - repeated 6 times
//use this starting frame to make the 'popover' appear small at first
CGRect startFrame = CGRectMake(10, 10, 10, 10);
self.view1 = [[UIView alloc] initWithFrame:startFrame];
[self.view addSubview:self.view1];
[UIView animateWithDuration:0.5 animations:^(void){
self.view1.layer.cornerRadius = 10;
self.view1.layer.borderColor = [UIColor blackColor].CGColor;
self.view1.layer.borderWidth = .5;
[self.view1 setBackgroundColor:[UIColor lightGrayColor]];
self.view1.frame = view1Frame;
} completion:^(BOOL finished){
[self.view1 addSubview:self.labelM];
[self.view1 addSubview:self.switchM];
//repeat 6 times for other labels & switches
}];
}
else {
[UIView animateWithDuration:0.3 animations:^() {
self.view1.frame = view1Frame;
} completion:^(BOOL finished) {
self.labelM.frame = labelMR;
self.switchM.frame = switchMR;
//repeated for the other 6
self.backButton.frame = backButtonR;
self.saveButton.frame = saveButtonR;
}];
}
}
-(void) hideBox{
//back button was selected
[UIView animateWithDuration:0.5 animations:^(void){
[self.view1 removeFromSuperview];
self.view1 = nil;
}];
}
I understand that as i'm doing/calling this via code, i need to override either init or initWithFrame:. Do i pass the initWithFrame: the containing view controllers bounds, of which the custom view can be calculated on, and how do i handle the animation?
I've managed to set up the delegate protocol which will notify when the save button is pressed. that part i understand, its just the rest of the parts i'm unclear on.
First some background.
Typically for a popover controller, you have a single transparent root view which contains the popover view itself. This root view is the size of the containing window and usually higher in z-order than all other views. There are two reasons for this:
1) The popover needs to draw on top of all other views. If the root view wasn't on top of all other views, the popover could be clipped and not draw all of its contents.
2) The user usually needs some place to tap and dismiss the popover (effectively a cancel action).
UIPopoverController does this as do some 3rd party popovers. Some even go so far as to use their own UIWindows.
To answer your specific questions:
1) initWithFrame: / setFrame: should be passed a CGRect that is in the coordinate space of the view that will contain the view. In other words, the superview. If you decide to use a transparent root view, the popover (the part that draw on screen) will be passed a CGRect in the coordinate space of the transparent root view.
2) Usually a popover is animated like so:
// set initial frame
popover.frame = CGRectMake(x, y, width, 0);
popover.alpha = 0.0;
[rootView addSubview:popover];
[UIView animateWithDuration:0.5
animations:^{
CGRect frame = popover.frame;
frame.size.height = some-height;
popover.frame = frame;
popover.alpha = 1;
}
];
I actually got it to work! (although i can't promise this is the cleanest or most resourceful way - we'll work on that).
Here's what i did:
Split the makeBox function into 3 function, initWithWidth:andHeight:forView, openBox & updateBoxWithWidth:andHeight.
I used a saveButton delegate method that informs the parent that save button has been pressed.
.h
#protocol BoxDelegate
-(void) daysChanged;
#end
__weak id <BoxDelegate> delegate;
#interface aBox : UIView
#property (nonatomic) BOOL monday;
#property (nonatomic, weak) id <BoxDelegate> delegate;
//property values for the custom view
-(id) initWithWidth: (CGFloat) width andHeight: (CGFloat) height withView: (UIView*) theView;
-(void) updateViewWithWidth: (CGFloat) width andHeight: (CGFloat) height;
-(void) openBox;
#end
.m
#synthesize delegate;
-(id) initWithWidth:(CGFloat)inWidth andHeight:(CGFloat)inHeight withView: (UIView*) theView{
self = [super init];
self.mainView = theView;
//super view bounds
self.viewWidth = inWidth;
self.viewHeight = inHeight;
//red box x, y & size
CGFloat startx = (self.viewWidth / 100) * 10;
CGFloat starty = (self.viewHeight /100) * 20;
self.width = (self.viewWidth / 100) * 80;
self.height = (self.viewHeight /100) * 70;
self.view1Frame = CGRectMake(startx, starty, self.width, self.height);
//label & switch frame
self.labelMR = CGRectMake(10, ((self.height / 100) * 12), ((self.width / 100) * 80) - 7.5, 25);
self.switchMR = CGRectMake(((self.width / 100) * 80) + 7.5, ((self.height / 100) * 11), ((self.width / 100) * 10), 15);
//repeated for the other 6
self.backButtonR = CGRectMake(5, 5, 50, 35);
self.saveButtonR = CGRectMake((self.width - 50), 5, 50, 35);
self.switchM = [[UISwitch alloc] initWithFrame:self.switchMR];
self.switchM.tag = 10;
if(self.monday){
self.switchM.on = true;
} else{
self.switchM.on = false;
}
[self.switchM addTarget:self action:#selector(switched:) forControlEvents:UIControlEventTouchUpInside];
self.labelM = [[UILabel alloc] initWithFrame:self.labelMR];
self.labelM.layer.masksToBounds = YES;
self.labelM.layer.cornerRadius = 5;
self.labelM.layer.borderColor = [UIColor blackColor].CGColor;
self.labelM.layer.borderWidth = .5;
self.labelM.text = #" Monday";
self.labelM.backgroundColor = [UIColor whiteColor];
//repeated for the other 6
self.saveButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[self.saveButton addTarget:delegate
action:#selector(daysChanged)
forControlEvents:UIControlEventTouchUpInside];
[self.saveButton setTitle:#"Save" forState:UIControlStateNormal];
self.saveButton.frame = self.saveButtonR;
return self;
}
-(void) openBox{
CGRect startFrame = CGRectMake(10, 10, 10, 10);
self.view1 = [[UIView alloc] initWithFrame:startFrame];
[self.mainView addSubview:self.view1];
[UIView animateWithDuration:0.5 animations:^(void){
self.view1.layer.cornerRadius = 10;
self.view1.layer.borderColor = [UIColor blackColor].CGColor;
self.view1.layer.borderWidth = .5;
[self.view1 setBackgroundColor:[UIColor lightGrayColor]];
// repeated for the other 6
self.view1.frame = self.view1Frame;
} completion:^(BOOL finished){
[self.view1 addSubview:self.labelM];
[self.view1 addSubview:self.switchM];
[self.view1 addSubview:self.backButton];
[self.view1 addSubview:self.saveButton];
}];
}
-(void) updateViewWithWidth: (CGFloat) width andHeight:(CGFloat) height{
//re-calculate
self.viewWidth = width;
self.viewHeight = height;
CGFloat startx = (self.viewWidth / 100) * 10;
CGFloat starty = (self.viewHeight /100) * 20;
self.width = (self.viewWidth / 100) * 80;
self.height = (self.viewHeight /100) * 70;
self.view1Frame = CGRectMake(startx, starty, self.width, self.height);
//label & switch frame
self.labelMR = CGRectMake(10, ((self.height / 100) * 12), ((self.width / 100) * 80) - 7.5, 25);
self.switchMR = CGRectMake(((self.width / 100) * 80) + 7.5, ((self.height / 100) * 11), ((self.width / 100) * 10), 15);
self.backButtonR = CGRectMake(5, 5, 50, 35);
self.saveButtonR = CGRectMake((self.width - 50), 5, 50, 35);
[UIView animateWithDuration:0.3 animations:^() {
self.view1.frame = self.view1Frame;
} completion:^(BOOL finished) {
self.labelM.frame = self.labelMR;
self.switchM.frame = self.switchMR;
self.backButton.frame = self.backButtonR;
self.saveButton.frame = self.saveButtonR;
}];
}
And then in our parent viewcontroller
#property aBox *theBox;
...
- (void)viewDidLoad {
[super viewDidLoad];
self.theBox = [[aBox alloc] initWithWidth:self.view.frame.size.width andHeight:self.view.frame.size.height withView:self.view];
[self.theBox openBox];
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
[self.theBox updateViewWithWidth:self.view.frame.size.width andHeight:self.view.frame.size.height];
}
- (void) daysChanged{
NSLog(#"Days Changed!");
}

UILabel auto scroll like a marquee

I am trying I make a UI label auto scroll the text that is inside it like a marquee. The below code works depending on what kind of text/content I throw at it. I can't tell what works and what does not. What happens is that the label does not show anything, then suddenly scrolls the text at an extremely high speed that you can't read it.
For some reason, this works perfectly on the iPhone but not on the iPad. I am guessing because the text I am putting at the iPhone is always way bigger than the Uilabel's size?
Here is the code:
self.currentTrack.textColor = [UIColor colorWithRed:15.0/255.0 green:176.0/255.0 blue:223.0/255.0 alpha:1];
self.currentTrack.labelSpacing = 35; // distance between start and end labels
self.currentTrack.pauseInterval = 1.7; // seconds of pause before scrolling starts again
self.currentTrack.scrollSpeed = 30; // pixels per second
self.currentTrack.textAlignment = NSTextAlignmentCenter; // centers text when no auto-scrolling is applied
self.currentTrack.fadeLength = 12.f;
self.currentTrack.scrollDirection = CBAutoScrollDirectionLeft;
[self.currentTrack observeApplicationNotifications];
}
Here is the code:
AutoScrollLabel, extended from UIView (code provided below) has an instance method to set text (setLabelText). The text provided will auto scroll only if the length of the text is bigger than the width of the AutoScrollLabel view.
Eg:
AutoScrollLabel *autoScrollLabel = [[AutoScrollLabel alloc] initWithFrame:CGRectMake(0, 0, 150, 25)];
[autoScrollLabel setLabelText:#"Some lengthy text to be scrolled"];
Note: You can make changes in setLabelText: Method implementation to support Attributed Text (use appropriate methods to find size of Attributed Text)
*** AutoScrollLabel.h
#interface AutoScrollLabel : UIView {
UILabel *textLabel;
NSTimer *timer;
}
- (void) setLabelText:(NSString*) text;
- (void) setLabelFont:(UIFont*)font;
- (void) setLabelTextColor:(UIColor*)color;
- (void) setLabelTextAlignment:(UITextAlignment)alignment;
#end
**** AutoScrollLabel.m
#import "AutoScrollLabel.h"
#import <QuartzCore/QuartzCore.h>
#implementation AutoScrollLabel
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.clipsToBounds = YES;
self.autoresizesSubviews = YES;
textLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
textLabel.backgroundColor = [UIColor clearColor];
textLabel.textColor = [UIColor blackColor];
textLabel.textAlignment = UITextAlignmentRight;
[self addSubview:textLabel];
}
return self;
}
-(void) setLabelText:(NSString*) text {
textLabel.text = text;
CGSize textSize = [text sizeWithFont:textLabel.font];
if(textSize.width > self.frame.size.width) {
textLabel.frame = CGRectMake(0, 0, textSize.width, self.frame.size.height);
}
else {
textLabel.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
}
if(textLabel.frame.size.width > self.frame.size.width) {
[timer invalidate];
timer = nil;
CGRect frame = textLabel.frame;
frame.origin.x = self.frame.size.width-50;
textLabel.frame = frame;
timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(moveText) userInfo:nil repeats:YES];
}
else {
[timer invalidate];
timer = nil;
}
}
-(void) moveText {
if(textLabel.frame.origin.x < textLabel.frame.size.width-2*textLabel.frame.size.width) {
CGRect frame = textLabel.frame;
frame.origin.x = self.frame.size.width;
textLabel.frame = frame;
}
[UIView beginAnimations:nil context:nil];
CGRect frame = textLabel.frame;
frame.origin.x -= 5;
textLabel.frame = frame;
[UIView commitAnimations];
}
- (void) setLabelFont:(UIFont*)font {
textLabel.font = font;
}
- (void) setLabelTextColor:(UIColor*)color {
textLabel.textColor = color;
}
- (void) setLabelTextAlignment:(UITextAlignment)alignment {
textLabel.textAlignment = alignment;
}
For Swift5
set top of your UILabel equal to superview bottom, and then use this code:
func createAnimationLbl() -> CAAnimation {
let animation = CABasicAnimation(keyPath: "transform.translation.y")
animation.fromValue = 0
animation.toValue = -(self.view.frame.height )
animation.duration = 15
animation.repeatCount = Float.infinity //times of scrolling, infinity for unlimited times.
animation.timingFunction = CAMediaTimingFunction.init(name: CAMediaTimingFunctionName.linear)
animation.fillMode = CAMediaTimingFillMode.forwards
animation.isRemovedOnCompletion = false
return animation
}
then in your viewWillAppear call it as below:
self.aboutLbl.layer.add(createAnimationLbl(), forKey: nil)

How to rotate button back to horizontal?

I'm making a circle with different buttons all over, spaced out at equal intervals.
Here's what it looks like :
I want to make it so that the picture doesn't rotate. How do I achieve that ? Here's the code.
- (void)drawWheel
{
// Drawing the Wheel view
wheelView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 275, 275)];
wheelView.center = self.view.center;
wheelView.layer.cornerRadius = wheelView.frame.size.width / 2.0;
wheelView.layer.borderColor = [UIColor whiteColor].CGColor;
//wheelView.layer.borderWidth = 0.5f;
CGFloat angleSize = 2 * M_PI / self.buttons.count;
for(int i = 0; i < self.buttons.count; i++)
{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, wheelView.frame.size.width / 2.0, 40)];
label.layer.anchorPoint = CGPointMake(1.0f, 0.5f);
label.layer.position = CGPointMake(wheelView.bounds.size.width / 2.0, wheelView.bounds.size.height / 2.0);
label.transform = CGAffineTransformMakeRotation(angleSize * i);
label.backgroundColor = [UIColor clearColor];
UIButton *button = [self.buttons objectAtIndex:i];
button.center = CGPointMake(label.center.x, label.center.y + 15);
button.transform = CGAffineTransformRotate(label.transform, 2 * (angleSize * i));
[label addSubview:button];
[wheelView addSubview:label];
}
[self.view addSubview:wheelView];
}
I didn't check it, but could you change following code
button.transform = CGAffineTransformRotate(label.transform, 2 * (angleSize * i));
to
button.transform = CGAffineTransformMakeRotation(-1 * angleSize * i);
Here I am just rotating your button to opposite direction
You could do something like this I think...
- (void)drawWheel
{
// Drawing the Wheel view
wheelView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 275, 275)];
wheelView.center = self.view.center;
wheelView.layer.cornerRadius = wheelView.frame.size.width / 2.0;
wheelView.layer.borderColor = [UIColor whiteColor].CGColor;
//wheelView.layer.borderWidth = 0.5f;
CGFloat angleSize = 2 * M_PI / self.buttons.count;
for(int i = 0; i < self.buttons.count; i++)
{
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, wheelView.frame.size.width / 2.0, 40)];
label.layer.anchorPoint = CGPointMake(1.0f, 0.5f);
label.layer.position = CGPointMake(wheelView.bounds.size.width / 2.0, wheelView.bounds.size.height / 2.0);
label.transform = CGAffineTransformMakeRotation(angleSize * i);
label.backgroundColor = [UIColor clearColor];
UIButton *button = [self.buttons objectAtIndex:i];
button.center = CGPointMake(label.center.x, label.center.y + 15);
// change this line
button.transform = CGAffineTransformMakeRotation(-angleSize * i);
[label addSubview:button];
[wheelView addSubview:label];
}
[self.view addSubview:wheelView];
}
Here I am just transforming the button in the other direction with the same angle.
i.e. if the label is rotated 35 degrees then the button is rotated -35 degrees. This will mean the button is rotated 0 degrees relative to the sup review of the label.

Adding an indicator at the current touch position?

I am developing a color selector and using a circular gradient and a panGesture to pick the color.
Can I add a crosshair or something else to the current touch position?
I need the crosshair to be visible but it should not interfere with the gradient.
This is the code that adds the gradient :
- (void)viewDidLoad
{
[super viewDidLoad];
CGSize size = CGSizeMake(self.view.bounds.size.width, ((self.view.bounds.size.height)/2));
UIGraphicsBeginImageContextWithOptions(CGSizeMake(size.width, size.height), YES, 0.0);
[[UIColor whiteColor] setFill];
UIRectFill(CGRectMake(0, 0,size.width,size.height));
int sectors = 180;
float radius = MIN(size.width, size.height)/2;
float angle = 2 * M_PI/sectors;
UIBezierPath *bezierPath;
for ( int i = 0; i < sectors; i++)
{
CGPoint center = CGPointMake(((size.width)/2), ((size.height)/2));
bezierPath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:i * angle endAngle:(i + 1) * angle clockwise:YES];
[bezierPath addLineToPoint:center];
[bezierPath closePath];
UIColor *color = [UIColor colorWithHue:((float)i)/sectors saturation:1. brightness:1. alpha:1];
[color setFill];
[color setStroke];
[bezierPath fill];
[bezierPath stroke];
}
img = UIGraphicsGetImageFromCurrentImageContext();
gradientView = [[UIImageView alloc]initWithImage:img];;
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(handlePan:)];
colorView = [[UIView alloc] init];
colorView.frame = CGRectMake(0, 00, 50, 50);
rText.textAlignment = NSTextAlignmentCenter;
gText.textAlignment = NSTextAlignmentCenter;
bText.textAlignment = NSTextAlignmentCenter;
saturationText.textAlignment = NSTextAlignmentCenter;
alphaText.textAlignment = NSTextAlignmentCenter;
brightnessText.textAlignment = NSTextAlignmentCenter;
rText.keyboardType = UIKeyboardTypeNumberPad;
gText.keyboardType = UIKeyboardTypeNumberPad;
bText.keyboardType = UIKeyboardTypeNumberPad;
saturationText.keyboardType = UIKeyboardTypeNumberPad;
alphaText.keyboardType = UIKeyboardTypeNumberPad;
brightnessText.keyboardType = UIKeyboardTypeNumberPad;
gradientView.frame = CGRectMake(0,0,size.width,size.height);
self.view.backgroundColor = [UIColor whiteColor];
[self.view addSubview:gradientView];
gradientView.userInteractionEnabled = YES;
[gradientView addGestureRecognizer: panGesture];
[self.view addSubview:colorView];
}
The handlePan method :
- (IBAction)handlePan:(UIPanGestureRecognizer *)sender
{
if (sender.numberOfTouches)
{
CGSize size = CGSizeMake(self.view.bounds.size.width, (self.view.bounds.size.height)/2);
float radius = MIN(size.width, size.height)/2;
[alphaSlider addTarget:self action:#selector(changeOpacity:) forControlEvents:UIControlEventValueChanged];
[hellSlider addTarget:self action:#selector(changeBrightness:) forControlEvents:UIControlEventValueChanged];
[saturationSlider addTarget:self action:#selector(saturate:) forControlEvents:UIControlEventValueChanged];
[rSlider addTarget:self action:#selector(redSlider:) forControlEvents:UIControlEventValueChanged];
[gSlider addTarget:self action:#selector(greenSlider:) forControlEvents:UIControlEventValueChanged];
[bSlider addTarget:self action:#selector(blueSlider:) forControlEvents:UIControlEventValueChanged];
CGPoint lastPoint = [sender locationOfTouch: sender.numberOfTouches - 1 inView: gradientView];
CGPoint center = CGPointMake((size.width/2), (size.height /2));
CGPoint delta = CGPointMake(lastPoint.x - center.x, lastPoint.y - center.y);
CGFloat angle = (delta.y == 0 ? delta.x >= 0 ? 0 : M_PI : atan2(delta.y, delta.x));
angle = fmod(angle, M_PI * 2.0);
angle += angle >= 0 ? 0 : M_PI * 2.0;
if((lastPoint.x - center.x) + (lastPoint.y - center.y)/2 < radius)
{
UIColor *color = [UIColor colorWithHue: angle / (M_PI * 2.0) saturation:saturationSlider.value brightness:hellSlider.value alpha:alphaSlider.value];
if ([color getRed: &r green: &g blue:&b alpha: &a])
{
NSLog(#"Color value - R : %g G : %g : B %g", r*255, g*255, b*255);
}
float red = r;
float green = g;
float blue = b;
rText.text = [NSString stringWithFormat:#"%.0f",rSlider.value];
gText.text = [NSString stringWithFormat:#"%.0f",green*255];
bText.text = [NSString stringWithFormat:#"%.0f",blue*255];
colorView.backgroundColor = [UIColor colorWithRed:(rText.text.floatValue/255) green:(gText.text.floatValue/255) blue:(bText.text.floatValue/255) alpha:alphaSlider.value];
rSlider.value = red*255;
gSlider.value = green*255;
bSlider.value = blue*255;
alphaText.text = [NSString stringWithFormat:#"%.2f",alphaSlider.value];
brightnessText.text = [NSString stringWithFormat:#"%.2f",hellSlider.value];
saturationText.text = [NSString stringWithFormat:#"%.2f",saturationSlider.value];
}
}
}
Question is solved, thank you.
Well, you definitely 'can' add a crosshair at your current touch position.
I can tell you one of the many possible ways of doing this.
Implement the
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer
action handler.
Load an image of a crosshair into an UIImage (say overlayImage):
overlayImage =[UIImage imageNamed:#"crosshair.png"];
and set it into an UIView (say overlayView).
[This can be done in your viewDidLoad method itself.]
Now, add the following code to your handlePan method:
CGPoint translation = [recognizer translationInView:colorView]; //whichever view you want.
_overlayView.center = CGPointMake(_overlayView.center.x + translation.x,
_overlayView.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:colorView];
if (recognizer.state == UIGestureRecognizerStateEnded) {
CGPoint velocity = [recognizer velocityInView:colorView];
CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));
CGFloat slideMult = magnitude / 800;
// NSLog(#"magnitude: %f, slideMult: %f", magnitude, slideMult);
float slideFactor = 0.1 * slideMult; // Increase for more of a slide
CGPoint finalPoint = CGPointMake(_overlayView.center.x + (velocity.x * slideFactor),
_overlayView.center.y + (velocity.y * slideFactor));
finalPoint.x = MIN(MAX(finalPoint.x, 0), colorView.bounds.size.width);
finalPoint.y = MIN(MAX(finalPoint.y, 0), colorView.bounds.size.height);
[UIView animateWithDuration:slideFactor*2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
_overlayView.center = finalPoint;
} completion:nil];
That should do the trick.
You may also try doing this by implementing the touchesBegan and touchesMoved method.

Resources