Creating a scalable Image button in iOS. Without a blurry image. - ios

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.

Related

animateWithDuration can't animating UIButton's bounds after UIButton has set an image

After I had set an image to an UIButton called bigIcon, I put it inside animateWithDuration with the change of its frame, then I ran the code, the button size changed instantly (has no animation), but it move from origin to destination slowly (has animation), how can I solve this problem? I found out that if I did set an image to the button this problem will disappear.
here is the code:
- (void)bigImage:(MCGodCell *)godCell withImage:(UIImage *)image {
self.bigIcon = [UIButton new];
self.bigIcon.adjustsImageWhenHighlighted = NO;
[self.bigIcon setBackgroundImage:image forState:UIControlStateNormal];
CGFloat iconX = self.tableView.frame.size.width / 2.0;
CGFloat iconY = self.tableView.frame.size.height / 2.0;
self.bigIcon.frame = CGRectMake(iconX, iconY, 1, 1);
[self.tableView addSubview:self.bigIcon];
CGFloat iconW = self.tableView.frame.size.width;
CGFloat iconH = iconW;
iconY = (self.view.frame.size.height - iconH) / 2.0;
[UIView animateWithDuration:0.3 animations:^{
self.bigIcon.frame = CGRectMake(0, iconY, iconW, iconH);
}];
}
You're not seeing the frame change because you're trying to animate it immediately after adding it to the view hierarchy.
UIKit needs to add the button as a subview, and then run the animation on the next UI update pass.
Wrap your animation block inside a dispatch_async block like this:
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.3 animations:^{
self.bigIcon.frame = CGRectMake(0, iconY, iconW, iconH);
}];
});

Rotate UIButton on change of orientation

I have round button which consists of the following image
Now on rotation of device I want to rotate the button in a way that the image maintains the orientation.
How can I achieve this,
I do not want to change the frame of the button i want it to stay where it is I just want to transform the button.
If you have an IBOutlet Object.
theButton.transform = CGAffineTransformMakeRotation(M_PI / -4);
If you want to create run time button on view.
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *btn=[UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn setFrame:CGRectMake(100, 100, 200, 44)];
btn.transform=CGAffineTransformMakeRotation(M_PI / -4);
[btn setTitle:#"RakeshBhatt" forState:UIControlStateNormal];
[self.view addSubview:btn];
}
To rotate a image view try this
// Set the anchor point and center so the view swings from the upper right
imageView.layer.anchorPoint = CGPointMake(1.0, 0.0);
imageView.center = CGPointMake(CGRectGetWidth(self.view.bounds), 0.0);
// Rotate 90 degrees to hide it off screen
CGAffineTransform rotationTransform = CGAffineTransformIdentity;
rotationTransform = CGAffineTransformRotate(rotationTransform, DegreesToRadians(90));
swingView.transform = rotationTransform;

UI help for Horizontal Color Picker

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.

Drop image and release when it goes out of bounds

I am new to programming in Objective-C, and am currently having an issue with the code below. I am trying to make an image drop when a button is touched, and it simply freezes when trying to do so. It needs to drop the image until it reaches the bottom of the screen, which then it should be released.
- (IBAction)itemDrop:(UIButton *)sender{
if (strncmp([[sender currentTitle] UTF8String], [copyPrimaryArray[0] UTF8String], 2) == 0)
{
UIImage *bubblImage = [UIImage imageNamed:#"Red_apple.png"];
UIImageView *appleImg = [[UIImageView alloc] initWithImage:bubblImage];
appleImg.translatesAutoresizingMaskIntoConstraints = NO;
[appleImg setContentMode:UIViewContentModeScaleAspectFit];
[appleImg sizeToFit];
[self.view addSubview:appleImg];
NSLog(#"You clicked the Apple");
int i = 0;
CGPoint coordinates = sender.frame.origin;
CGFloat x = coordinates.x;
CGFloat y = coordinates.y;
CGFloat z = UIScreen.mainScreen.bounds.size.height;
while (y < z) {
[UIView beginAnimations:nil context:nil];
appleImg.center = CGPointMake(x, y+i);
[UIView commitAnimations];
i++;
}
}
}
You do not need to move the image view one point at a time manually. That's what I seem to understand from your use of the while loop. Objective-c does a lot of things for you.
UIImage *bubblImage = [UIImage imageNamed:#"Red_apple.png"];
UIImageView *appleImg = [[UIImageView alloc] initWithImage:bubblImage];
// Set the frame of the original position here, for example:
CGRect originalPosition = CGRectMake(0, 0, appleImg.frame.size.width, appleImg.frame.size.height);
appleImg.frame = originalPosition;
// Then animate it to the new position:
[UIView animateWithDuration:1.0
animations:^{
CGRect newPosition = CGRectMake(0, 640, appleImg.frame.size.width, appleImg.frame.size.height);
appleImg.frame = newPosition;
}
completion:^(BOOL finished) {
NSLog(#"completion block"); // You can set the completion block to nil if you have nothing to do here.
}];
Make sure to start using block based animations.
The use of UIView's beginAnimations:context is highly discouraged since iOS 4.0.

Graphical glitch in UIScrollView when autorotating device

I have an application which has a fullscreen UIScrollView, and within it there are seven images. The images are also meant to be full screen, and the scroll view is set to enable pagination.
I have a method which either creates or moves the image views:
-(void)rebuildImageView{
// set up images
float screenW = self.view.bounds.size.width;
float screenH = self.view.bounds.size.height;
int numImgs = self.soundNames.count;
self.mainScrollView.contentSize = CGSizeMake(screenW * numImgs, screenH);
for(int i=0; i<numImgs; i++){
UIImageView* imageView = (UIImageView*)[self.mainScrollView viewWithTag:i+100];
if(imageView == nil){
imageView = [[UIImageView alloc] init];
imageView.tag = i+100;
[self.mainScrollView addSubview:imageView];
imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"image%d.jpg",i]];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.clipsToBounds = YES;
[imageView release];
}
imageView.frame = CGRectMake(i * screenW, 0, screenW, screenH);
}
// scroll to the current one
[self.mainScrollView scrollRectToVisible:CGRectMake(self.currentSound*screenW, 0, screenW, screenH) animated:YES];
}
I also have this on the view controller:
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[UIView animateWithDuration:duration animations:^{
[self rebuildImageView];
}];
}
This code works fine when I autorotate while image 0 is being shown, but when I'm on image 7, you can briefly see most of image 6 when rotating. This video shows what's happening:
http://www.youtube.com/watch?v=1O3jOcTgVP8
Is there a better method I should use to reconfigure the scroll view and images when rotating the device?
Any frame changes put in the willAnimateRotationToInterfaceOrientation:duration method should automatically animate. So you could try removing it from the block?
Personally, I've had a lot more luck with this type of thing subclassing UIScrollView and putting the equivalent layout subview frame code in an override of the layoutSubviews method (don't forget to call super or you might end up with misplaced scroll bars).

Resources