In iOS Objective C, I need the text fill animation with gradient, the animation will fill the gradient from bottom to top (Vertically). I am not good in core graphics or animation things in iOS.
Has anyone did this kind of task before.
Any help would be really appreciated.
Here is an idea. Use two labels and animate the second one in. This has its limits, to go further you need to either use the labels' layers or to convert it to UIImage's and then animate that in. This animates from the center out which is not entirely what you are looking for, but just an idea for now.
The storyboard contains just one button which you need to wire up to kick off the animation.
EDIT
Previously it animated from the center outwards but I've changed it to animate from the bottom to the top.
- ( void ) viewDidLoad
{
[super viewDidLoad];
// Start label
UILabel * label = [[UILabel alloc] initWithFrame:CGRectMake ( 10, 50, 100, 20 )];
// Configure
label.text = #"Label";
label.textColor = UIColor.redColor;
label.sizeToFit;
[self.view addSubview:label];
// The label we animate in
UILabel * label1 = [[UILabel alloc] initWithFrame:CGRectMake ( 10, 50, 100, 20 )];
// Configure
label1.text = #"Label";
label1.textColor = UIColor.blueColor;
label1.clipsToBounds = YES;
label1.contentMode = UIViewContentModeBottom;
label1.sizeToFit;
// We keep a weak reference to it
[self.view addSubview:label1];
self.label1 = label1;
}
- ( IBAction ) buttonAction:( id ) sender
{
CGRect f = self.label1.frame;
CGRect b = self.label1.bounds;
// Need to animate both the bounds and the frame's position
self.label1.frame = CGRectMake( f.origin.x, f.origin.y + f.size.height / 2, f.size.width, f.size.height );
self.label1.layer.bounds = CGRectMake( 0, 0, b.size.width, 0 );
[UIView animateWithDuration:2
animations:^{
self.label1.frame = f;
self.label1.layer.bounds = b;
}];
}
Note that you need to add a weak property to the view controller, e.g.
#property (nonatomic,weak) UILabel * label1;
as you need this later to be able to animate.
I am trying to make color picker by reading pixel of imageview. Right now I have one imageview in the background and retrieving pixel color from it.
But now i am looking to shift my UI like this, so need help in how should I make this UI
Here's what I thought this will loo like
UIView->n no of. Imageview and arrow will be on top of it.
But then there are few things that I am not sure how will I do it
I have to keep some color unlock as level is crossed colors will get unlock
knob should not go outside the bound
I have to retrieve the color from the edge of the arrow so that I get the proper pixel value
Here is my suggestion to how to deal with this,
Create a list of images and the color values for each of those in a
NSDictionary like,
NSDictionary *colors = #{[UIColor redColor]: [UIImage imageNamed:#"red"], [UIColor greenColor]: [UIImage imageNamed:#"green"], [UIColor yellowColor: [UIImage imageNamed:#"green"]]}
Then create the imageview and add the images to the view and add tap gesture recognizer to each of the imageViews;
UIView *parentView = self.parentView;
CGFloat knobHeight = 20;
CGFloat colorViewHeight = 20;
CGFloat colorViewWidht = 20;
int index = 0;
for(UIColor *color in colors){
CGRect frame = CGRectMake(index * colorViewWidth, knobHeight, colorViewWidth, colorViewHeight);
UIImageView *imageView = [[UIImageView alloc] initWithFrame: frame];
imageView.image = colors[color];
[parentView addSubView:imageView];
UITapGestureRecognizer *tapGestureRecognizer = [UITapGestureRecognizer alloc] initWithTarget: self selector:#selector(tappedImage:)];
imageView.userInteractionEnabled = YES;
[imageView addGestureRecognizer: tapGestureRecognizer];
}
Initially add knob to the first imageView;
UIImageView *firstImageView = [[parentView subView] firstObject];
CGRect knobFrame = CGRectMake (CGRectGetMidX(firstImageView.frame) - knobWidth / 2, 0, knobWidth, knobHeight);
UIImageView *knobImageView = [[UIImageView alloc] initWithFrame:knobFrame];
[parentView addSubview: knobImageView];
Then, in the tap selector you could animate the knob change as;
- (void)tappedImage:(UITapGestureRecognizer*)tap{
UIImageView *tappedImageView = tap.view;
CGRect newKnobFrame = CGRectMake((CGRectGetMidX(tappedImageView.frame) - knobWidth / 2, 0 , knobWidth, knobHeight);
[UIView animateWithDuration:2.0 animations:^{
knobImageView.frame = newKnobFrame;
}];
}
You could also keep track of the color for which you want to lock selection. Then, do not enable the userInteraction for those images and not add the gesture recognizer. You could set alpha value to show that it is not possible to select it.
This code is directly typed, but it should give you the rough idea of how it could work.
What am I trying to do:
I want to make a button that scales up or down depending on it's current state which is determined by it either being big or small.
When button is big and I press it, it becomes small. When the button is small and I press it, it becomes big.
The button must contain a image of a QR code and subsequently be scannable by a QR reader.
My problem:
Is that the image is blurry when big. This isn't the case if I put the image inside a ImageView instead of a button.
The effect is best described here:
http://imgur.com/a/h3rJg#0
The Code:
Button/Image Declaration
UIImage* image = [QREncoder encode:user];
// declare image - QREncoder can be found on github
UIImage *strechedBackground = [image stretchableImageWithLeftCapWidth:220 topCapHeight:220];
UIImageView* imageView = [[UIImageView alloc] initWithImage:image];
CGFloat qrSize = self.view.bounds.size.width - kPadding * 2;
CGRect largeFrame = CGRectMake(kPadding, (self.view.bounds.size.height - qrSize) / 2,
qrSize, qrSize);
imageView.frame = largeFrame;
[imageView layer].magnificationFilter = kCAFilterNearest;
//[self.view addSubview:imageView];
// add qr button to the view
self.qrButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.qrButton.frame = largeFrame;
[self.qrButton setBackgroundImage:image forState:UIControlStateNormal];
[self.qrButton addTarget:self
action:#selector(aMethod)
forControlEvents:UIControlEventTouchDown];
self.qrButton.contentMode = UIViewContentModeCenter;
[self.view addSubview:self.qrButton];
Button/Image Scale Function
- (void)aMethod{
// some variables concerned with button sizes and dimensions
CGFloat qrSize = self.view.bounds.size.width - kPadding * 2;
CGRect largeFrame = CGRectMake(kPadding, (self.view.bounds.size.height - qrSize) / 2,
qrSize, qrSize);
CGFloat smallButtonWidth = 33.0;
CGFloat smallButtonHeight = 33.0;
CGFloat largeButtonWidth = 264.0;
CGFloat largeButtonHeight = 264.0;
CGRect smallFrame = CGRectMake(self.view.frame.size.width - smallButtonWidth - kPadding/2, self.view.frame.size.height - smallButtonHeight - kPadding/2, smallButtonWidth, smallButtonHeight);
// a boolean ivar indicates the size of the button
if (!self.qrButtonIsBig){
NSLog(#"Button was Big");
// animate the view...
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
//self.qrButton.transform = CGAffineTransformMakeScale(3, 3);
// resting positon after animation
self.qrButton.frame = smallFrame;
}
completion:nil];
NSLog(#"Button is now Small");
}else{
NSLog(#"Button was Small");
// animate the view...
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.qrButton.transform = CGAffineTransformIdentity;
// resting positon after animation, bottom left with 20 px margin
self.qrButton.frame = largeFrame;
}
completion:nil];
NSLog(#"Button is now Big");
}
self.qrButtonIsBig = !self.qrButtonIsBig;
}
If you need your view to be sharper when it is resized then you need your CALayer class to be a CATiledLayer. you can subclass it in order to define how you will fill your tiles.
Check this question if you want to go this road
check this question if you don't want to use CATiledLayer
Since the ImageView was sharp and ButtonImage blurry. It makes sense to scale the imageview with an invisible button on top as a practical work around rather than trying to get the image to be sharp in the button.
Is this possible?
I want to change the alpha value of the navigation bar in my view controller (in an animation), but if I do self.navigationController.navigationBar.alpha = 0.0;, the portion of the screen the navigationBar took up totally disappears and leaves a black box, which is not what I'd like (I'd prefer it to be the color of self.view's background).
As I support Colin's answer, I want to give you an additional hint to customize the appearance of an UINavigationBar including the alpha.
The trick is to use UIAppearance for your NavigationBar. This enables you to assign an UIImage to your NavigationBar's backgroundImage. You can generate these UIImages programmatically and use for that UIColors and set the colors' alpha properties as you want. I've done this in one of my own applications and it works as expected.
Here I give you some code snippets:
E.g. in your ..AppDelegate.m add these lines in didFinishLaunchingWithOptions:
//create background images for the navigation bar
UIImage *gradientImage44 = nil; //replace "nil" with your method to programmatically create a UIImage object with transparent colors for portrait orientation
UIImage *gradientImage32 = nil; //replace "nil" with your method to programmatically create a UIImage object with transparent colors for landscape orientation
//customize the appearance of UINavigationBar
[[UINavigationBar appearance] setBackgroundImage:gradientImage44 forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setBackgroundImage:gradientImage32 forBarMetrics:UIBarMetricsLandscapePhone];
[[UINavigationBar appearance] setBarStyle:UIBarStyleDefault];
Implement convenience methods to programmatically creates UIImage objects, e.g. create a new category for UIImage:
//UIImage+initWithColor.h
//
#import <UIKit/UIKit.h>
#interface UIImage (initWithColor)
//programmatically create an UIImage with 1 pixel of a given color
+ (UIImage *)imageWithColor:(UIColor *)color;
//implement additional methods here to create images with gradients etc.
//[..]
#end
//UIImage+initWithColor.m
//
#import "UIImage+initWithColor.h"
#import <QuartzCore/QuartzCore.h>
#implementation UIImage (initWithColor)
+ (UIImage *)imageWithColor:(UIColor *)color
{
CGRect rect = CGRectMake(0, 0, 1, 1);
// create a 1 by 1 pixel context
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
[color setFill];
UIRectFill(rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Re-work your image creation in 1. (#import "UIImage+initWithColor.h" in AppDelegate.m and replace the "nil"s):
This is your spot of interest: by changing your colors' alpha property you are influencing the opacity level of you NavigationBar as well!
UIImage *gradientImage44 = [UIImage imageWithColor:[UIColor colorWithRed:1.0 green:0.0 blue:1.0 alpha:0.2]];
UIImage *gradientImage32 = [UIImage imageWithColor:[UIColor colorWithRed:1.0 green:0.0 blue:1.0 alpha:0.2]];
I created a small demo project and add you two screenshots:
the view itself has a yellow backgroundColor.
The backgroundImages of the NavigationBar have a red color.
Screenshot 1 shows a NavigationBar with a value for alpha = 0.2.
Screenshot 2 shows a NavigationBar with a value for alpha = 0.8.
The most straightforward way of doing this is modifying the alpha component of navigationBar background view, which at this time (iOS9) is a first navigationBar subview. Note however that we never know if the subview hierarchy will be changed by apple in later releases, so gotta be careful.
let navigationBackgroundView = self.navigationController?.navigationBar.subviews.first
navigationBackgroundView?.alpha = 0.7
Directly from the Apple Developer reference:
"there are only a handful of direct customizations you can make to the
navigation bar. Specifically, it is alright to modify the barStyle,
tintColor, and translucent properties, but you must never directly
change UIView-level properties such as the frame, bounds,
alpha, or hidden properties directly."
You can however set the translucence property of the navigation bar. If you do [self.navigationController.navigationBar setTranslucent:YES];
should solve your problem. You can also try seeing if any of the UIBarStyle enums are something you want.
MickBraun's answer in Swift:
In AppDelegate.swift add these lines in didFinishLaunchingWithOptions:
// create background images for the navigation bar
let gradientImage44 = UIImage.imageWithColor(UIColor(red: 1.0, green: 0.0, blue: 1.0, alpha: 0.2))
let gradientImage32 = UIImage.imageWithColor(UIColor(red: 1.0, green: 0.0, blue: 1.0, alpha: 0.2))
// customize the appearance of UINavigationBar
UINavigationBar.appearance().setBackgroundImage(gradientImage44, forBarMetrics: .Default)
UINavigationBar.appearance().setBackgroundImage(gradientImage32, forBarMetrics: .Compact)
UINavigationBar.appearance().barStyle = .Default
Implement convenience methods to programmatically create UIImage objects.
class func imageWithColor(colour: UIColor) -> UIImage {
let rect = CGRectMake(0, 0, 1, 1)
// Create a 1 by 1 pixel content
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
colour.setFill()
UIRectFill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
If you just want to get rid of the navigationBar in an animated way you could do:
[self.navigationController setNavigationBarHidden:YES animated:YES];
If you want to control the animation and its necessary to set the alpha to 0.0, read on:
The "black box" you are seeing is from the underlying view or window. If you just want your views color instead of the "black box" do:
self.navigationController.view.backgroundColor = self.view.backgroundColor;
[UIView animateWithDuration:1.0 delay:1.0 options:0 animations:^{
self.navigationController.navigationBar.alpha = 0.0;
} completion:NULL];
If you want your actual view to be where the navigationBar was, you need to increase the height of your view:
[UIView animateWithDuration:1.0 delay:1.0 options:0 animations:^{
self.navigationController.navigationBar.alpha = 0.0;
CGFloat navigationBarHeight = self.navigationController.navigationBar.frame.size.height;
CGRect frame = self.view.frame;
frame.origin.y -= navigationBarHeight;
frame.size.height += navigationBarHeight;
self.view.frame = frame;
} completion:NULL];
You have a few options depending, in part, upon the barStyle of your UINavigationBar. The main thing is realizing that you likely don't necessarily have to animate the alpha property to get the effect you're describing.
UIBarStyleDefault or UIBarStyleBlackOpaque Option A is to set your UINavigationBar translucent property to YES, then animate the alpha:
navigationBar.translucent = YES; // ideally set this early, in the nib/storyboard, or viewDidLoad
...
[UIView animateWithDuration: 1.0
animations: ^{
// toggle:
navigationBar.alpha = navigationBar.alpha == 0 ? 1.0 : 0.0;
}];
In this scenario your view will be positioned behind your navbar, even when its alpha is 1.0. The downside to this scenario is that even with a 1.0 alpha you might see a tinge of your view's background color behind the UINavigationBar. Also, all of your subviews will need to be positioned 44 points down from the top.
UIBarStyleDefault or UIBarStyleBlackOpaque Option B is to hide the navbar in a cross-disolve transition animation. This will expose the superview of the UINavigationBar. If you're using a UINavigationController then the black background of the UINavigationController view is what you'll see - but you can set the background color of the UINavigationController view to match your view to get the effect that you want:
UINavigationBar* navigationBar = self.navigationController.navigationBar;
self.navigationController.view.backgroundColor = self.view.backgroundColor;
[UIView transitionWithView: navigationBar
duration: 1.0
options: UIViewAnimationOptionTransitionCrossDissolve
animations: ^{
// toggle:
navigationBar.hidden = !navigationBar.hidden;
}
completion: nil];
One thing to watch out for with this solution might be a layout issue if the UINavigationController updates your view frame because you hid the UINavigationBar. This would be fine except that your subviews might shift up 44 pixels if they're anchored to the top left. To work around this you might consider anchoring your subviews to the bottom of your view instead (either with springs or with layout constraints).
UIBarStyleDefault or UIBarStyleBlackOpaque Option C is to cover up the UINavigationBar with another view, again using a cross-disolve transition animation:
UINavigationBar* navigationBar = self.navigationController.navigationBar;
[UIView transitionWithView: navigationBar
duration: 1.0
options: UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionAllowAnimatedContent
animations: ^{
// toggle:
const int tag = 1111;
UIView* navOverlayView = [navigationBar viewWithTag: tag];
if ( navOverlayView == nil )
{
navOverlayView = [[UIView alloc] initWithFrame: CGRectInset( navigationBar.bounds, 0, -3 ) ];
navOverlayView.backgroundColor = self.view.backgroundColor;
navOverlayView.tag = tag;
[navigationBar addSubview: navOverlayView];
}
else
{
[navOverlayView removeFromSuperview];
}
}
completion: nil];
UIBarStyleBlackTranslucent: This option is the easiest, as the UINavigationBar is already translucent, and your view is already behind it. Simply animate the alpha:
[UIView animateWithDuration: 1.0
animations: ^{
// toggle:
navigationBar.alpha = navigationBar.alpha == 0 ? 1.0 : 0.0;
}];
You can also try to set a background view underneath the navigation bar and modify this view directly.
private lazy var backgroundView: UIView = UIView()
...
private func setupNavigationBarBackground() {
guard let navigationBar = navigationController?.navigationBar else { return }
navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationBar.isTranslucent = true
view.addSubview(backgroundView)
backgroundView.alpha = 0
backgroundView.backgroundColor = .red
backgroundView.translatesAutoresizingMaskIntoConstraints = false
backgroundView.topAnchor.constraint(equalTo: topLayoutGuide.topAnchor).isActive = true
backgroundView.bottomAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true
backgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
backgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
}
private func changeNavigationBarAlpha(to alpha: CGFloat) {
backgroundView.alpha = alpha
}
This should get you the effect you desire:
self.navigationController.navigationBar.alpha = 0.0;
self.navigationController.navigationBar.frame = CGRectMake(0,0,320,0);
Did not try this in an animation, works in my viewDidAppear though, hope it works.
Swift3
var navAlpha = // Your appropriate calculation
self.navigationController!.navigationBar.backgroundColor = UIColor.red.withAlphaComponent(navAlpha)
My main UIViewController has a sub UIView named viewContainer. It has a couple of UIImageViews, UIButtons and UIViews added to it. In my viewDidLoad method I've applied the following to viewContainer:
self.viewContainer.layer.shadowColor = [UIColor blackColor].CGColor;
self.viewContainer.layer.shadowOffset = CGSizeMake(0, 0);
self.viewContainer.layer.shadowOpacity = 1.0;
self.viewContainer.layer.shadowRadius = 10.0;
self.viewContainer.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.viewContainer.layer.bounds].CGPath;
self.viewContainer.backgroundColor = [UIColor blackColor];
self.viewContainer.opaque = YES;
When a user presses a button inside the viewContainer, I perform the following translation:
[UIView animateWithDuration:0.3
animations:^{
[self.viewContainer setCenter: CGPointApplyAffineTransform(self.viewContainer.center, CGAffineTransformConcat(self.viewContainer.transform, CGAffineTransformMakeTranslation(60, 0)))];
}
completion:nil];
My problem is that at the end of the animation, the edge of the view flickers for a fraction of a second (a white vertical line). I've tried setting the frame instead of a transform but still the same result. I'm attempting to do a sort of slide to reveal options thing, which works but flickers on completion.
Any ideas?