Create a CAShapeLayer around UIButton? - ios

I have a UIButton, I want to create a BORDER outside its content.
I want to create it using CAShapeLayer or any other proper way.
How can I do so.
The property of borderColor and BorderWidth of UIButton creates a border inside the BUTTON. As more width, as more space is consumed from inside.
Thanks.

// This is the *.m file
#import "ViewController.h"
#interface ViewController ()
// Comment A. Another label and button added to the class without adding them to the
// storyboard
#property (nonatomic, strong) UIButton *firstButton;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.firstButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[self.firstButton setTitle:#"Just a Button" forState:UIControlStateNormal];
self.firstButton.frame = CGRectMake(50, 50, 300, 40);
UIGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(theAction:)];
[self.firstButton addGestureRecognizer:tapGesture];
//The screen width and height
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
CGFloat screenHeight = screenSize.height;
//The CALayer definition
CALayer *graphic = nil;
graphic = [CALayer layer];
graphic.bounds = CGRectMake(0, 0, screenHeight, screenWidth);
graphic.position = CGPointMake(screenHeight/2, screenWidth/2);
graphic.backgroundColor = [UIColor whiteColor].CGColor;
graphic.opacity = 1.0f;
[graphic addSublayer:self.firstButton.layer];
[self.view.layer addSublayer:graphic];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)theAction:(id)sender {
NSLog(#"Button Tapped");
}
#end

Related

Cannot pan UIScrollView after zooming

I've programatically created a UIScrollView using the following code:
.h:
#interface MainController : UIViewController <UIScrollViewDelegate>
#property (nonatomic, retain) UIScrollView *mainScrollView;
#property (nonatomic, retain) UIView *mainView;
.m:
- (void) initVariables
{
// Setters
screenRect = [[UIScreen mainScreen] bounds];
screenWidth = screenRect.size.width;
screenHeight = screenRect.size.height;
// Alloc-init methods
mainScrollView = [[UIScrollView alloc] init];
mainView = [[UIView alloc] init];
}
- (void) setUpScrollView
{
mainScrollView.frame = CGRectMake(0.0f, 0.0f, screenWidth, screenHeight);
mainScrollView.contentSize = CGSizeMake(screenWidth*2, screenHeight*2);
mainScrollView.minimumZoomScale = 1.0;
mainScrollView.maximumZoomScale = 4.0;
mainScrollView.backgroundColor = [UIColor blueColor];
mainScrollView.scrollEnabled = YES;
mainScrollView.delegate = self;
mainView.frame = CGRectMake((screenWidth/2) - 25.0f, (screenHeight/2) - 25.0f, 50.0f, 50.0f);
UIImageView *testImageView = [[UIImageView alloc] init];
testImageView.backgroundColor = [UIColor redColor];
testImageView.frame = CGRectMake(0.0f, 0.0f, 50.0f, 50.0f);
// Add subviews
[self.view addSubview:mainScrollView];
[mainScrollView addSubview:mainView];
[mainView addSubview:testImageView];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return mainView;
}
The zoom works well now. However, I can only pan when the UIScrollView is at the minimum zoom. All other times, when I pinch-zoom in, when I release my fingers the UIView shifts slightly off-centre, despite being centred when I was zooming, and I can no longer pan the UIScrollView.
Also, after zooming in, if I zoom back out again to minimum zoom, I still cannot pan.
TL;DR - In other words, UIScrollView's pan only before using the pinch zoom feature, after which it breaks.
How can I prevent this from happening, and allow the UIScrollView's pan to always be enabled? All help appreciated.
Try to add another view in scrollView with same size of screen and then add mainView and imageView. It may solve your proble. :)

UIScrollView for image pages not scrolling to next page

I have a UIImageView that contains four ImageView as subviews. Each ImageView acts as a page that the user can scroll forward and go to the next page (image). However, i am unable to achieve this scrolling to next page. It only shows the first image. Here is my implementation
TutorialViewController.h
#import <UIKit/UIKit.h>
#interface TutorialViewController : UIViewController{
}
#property (nonatomic, retain) IBOutlet UIScrollView *tutorialScrollView;
#end
TutorialViewController.m
#import "TutorialViewController.h"
#interface TutorialViewController () <UIScrollViewDelegate>
#end
#implementation TutorialViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.tutorialScrollView.pagingEnabled = YES;
self.tutorialScrollView.showsHorizontalScrollIndicator = NO;
self.tutorialScrollView.scrollEnabled = YES;
self.tutorialScrollView.delegate = self;
}
-(void)viewDidAppear:(BOOL)animated
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
UIImageView *page1 = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,screenWidth,screenHeight)];
page1.image = [UIImage imageNamed:#"tutorial1.png"];
UIImageView *page2 = [[UIImageView alloc] initWithFrame:CGRectMake(screenWidth * 2,0,screenWidth,screenHeight)];
page2.image = [UIImage imageNamed:#"tutorial2.png"];
UIImageView *page3 = [[UIImageView alloc] initWithFrame:CGRectMake(screenWidth * 3,0,screenWidth, screenHeight)];
page3.image = [UIImage imageNamed:#"tutorial3.png"];
UIImageView *page4 = [[UIImageView alloc] initWithFrame:CGRectMake(screenWidth * 4,0,screenWidth, screenHeight)];
page4.image = [UIImage imageNamed:#"tutorial4.png"];
[self.tutorialScrollView addSubview:page1];
[self.tutorialScrollView addSubview:page2];
[self.tutorialScrollView addSubview:page3];
[self.tutorialScrollView addSubview:page4];
}
#end
You should set contentSize for UIScrollView:
[self.tutorialScrollView setContentSize:CGSizeMake(screenWidth*numOfPages, screenHeight)];
You will need to set the ContentSize of the scrollView.
self.tutorialScrollView.contentSize = CGSizeMake(imageView.frame.size.width * numberOfImages, self.tutorialScrollView.frame.size.height);
This will scroll your scrollView in horizontal direction.

UiLabel text assignment in custom view

I have created a custom view (custom view) inside other custom view(bage). Then in main view I add custom view as a subview. After that I am trying to set text via property and it does not work.
Bage.h:
#import <UIKit/UIKit.h>
#interface Bage : UIView
#property (nonatomic,strong) UILabel *title;
#end
Bage.m:
#import "Bage.h"
#implementation Bage
#synthesize title;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:CGRectMake(0, 0, 45, 25)];
if (self) {
// Initialization code
}
return self;
}
- (void)drawRect:(CGRect)rect
{
//// General Declarations
CGContextRef context = UIGraphicsGetCurrentContext();
//// Shadow Declarations
UIColor* shadow = UIColor.blackColor;
CGSize shadowOffset = CGSizeMake(3.1, 3.1);
CGFloat shadowBlurRadius = 3;
//// Variable Declarations
CGFloat buttonWidth = rect.size.width - 2 - 4;
CGFloat buttonHeigh = rect.size.height - 2 - 4;
//// Frames
// CGRect frame = CGRectMake(frSize.origin.x, frSize.origin.y, frSize.size.width, frSize.size.height);
//// Rectangle Drawing
UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(1, 1, buttonWidth, buttonHeigh) cornerRadius: 8];
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, [shadow CGColor]);
[UIColor.whiteColor setFill];
[rectanglePath fill];
CGContextRestoreGState(context);
[[UIColor greenColor] setStroke];
rectanglePath.lineWidth = 1;
[rectanglePath stroke];
title = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMinX(rect) + 1, CGRectGetMinY(rect) + 1, CGRectGetWidth(rect) - 6, CGRectGetHeight(rect) - 6)];
title.textColor = [UIColor blackColor];
title.textAlignment = NSTextAlignmentCenter;
[self addSubview:title];
}
#end
CustomView.h
#import <UIKit/UIKit.h>
#import "Bage.h"
#interface CustomView : UIView
#property (nonatomic,strong) Bage *myBage;
#end
CustomView.m
#import "CustomView.h"
#implementation CustomView
#synthesize myBage;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
myBage = [[Bage alloc] init];
self.backgroundColor = [UIColor greenColor];
myBage.title.text = #"Class text";
myBage.center = self.center;
[self addSubview:myBage];
}
return self;
}
#end
ViewController.m
#import "ViewController.h"
#import "CustomView.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor blueColor];
CustomView *cView = [[CustomView alloc] initWithFrame:CGRectMake(30, 30, 200, 200)];
[self.view addSubview:cView];
cView.myBage.backgroundColor = [UIColor clearColor];
cView.myBage.title.text = #"Text";
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Please help me to get text in my bage.
Do not add the title as a subview in drawRect:. You should do this when the Bage view is initialized. Also, you are using the rect given to you in drawRect:, which will not always be the bounds of the view. So, add the title in your initializer

UIScrollView not scrolling horizontally with dynamic UIButtons

I am creating a customview which is a subclass of UIScrollView. I am adding UIButtons inside UIScrollView dynamically along with images and actions. But scrollview is not scrolling horizontally with buttons. I know this topic is discussed many times on SO. I tried all posts posted on SO, but not getting expected result. Any suggestion about where i am going wrong will be helpful.
MyCustomView.h
#interface MyCustomView : UIScrollView
#property (strong, nonatomic) IBOutlet UIScrollView *scrollView;
+ (id)customView;
#end
MyCustomView.m
#implementation MyCustomView
#synthesize scrollView;
+ (id)customView
{
MyCustomView *customView = [[[NSBundle mainBundle] loadNibNamed:#"MyCustomView" owner:nil options:nil] lastObject];
if ([customView isKindOfClass:[MyCustomView class]])
return customView;
else
return nil;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
- (void)drawRect:(CGRect)rect
{
[self setupHorizontalScrollView];
}
- (void)setupHorizontalScrollView
{
//scrollView.delegate = self;
[self.scrollView setBackgroundColor:[UIColor blueColor]];
[scrollView setCanCancelContentTouches:YES];
scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView.clipsToBounds = NO;
scrollView.scrollEnabled = YES;
//scrollView.pagingEnabled = YES;
CGFloat cx = 0;
NSArray *buttons = #[#{#"Tag":#1,#"Image":[UIImage imageNamed:#"borderImage1.png"]},
#{#"Tag":#2,#"Image":[UIImage imageNamed:#"borderImage2.png"]},
#{#"Tag":#3,#"Image":[UIImage imageNamed:#"borderImage3.png"]},
#{#"Tag":#4,#"Image":[UIImage imageNamed:#"borderImage4.png"]},
#{#"Tag":#1,#"Image":[UIImage imageNamed:#"borderImage1.png"]},
#{#"Tag":#2,#"Image":[UIImage imageNamed:#"borderImage2.png"]},
#{#"Tag":#3,#"Image":[UIImage imageNamed:#"borderImage3.png"]},
#{#"Tag":#4,#"Image":[UIImage imageNamed:#"borderImage4.png"]},
#{#"Tag":#1,#"Image":[UIImage imageNamed:#"borderImage1.png"]}
];
// CGRect frame = CGRectMake(0.0f, 0.0f, 50.0f, 30.0f);
for (NSDictionary *dict in buttons)
{
UIButton *button =[UIButton buttonWithType:UIButtonTypeRoundedRect];
CGRect rect = button.frame;
rect.size.height = 40;
rect.size.width = 40;
rect.origin.x = cx;
rect.origin.y = 0;
button.frame = rect;
button.tag = [dict[#"Tag"] integerValue];
[button setImage:dict[#"Image"]
forState:UIControlStateNormal];
// [button addTarget:self action:#selector(buttonAction:)
// forControlEvents:UIControlEventTouchUpInside];
[self.scrollView addSubview:button];
//frame.origin.x+=frame.size.width+20.0f;
cx += button.frame.size.width+5;
}
[scrollView setContentSize:CGSizeMake(cx, [scrollView bounds].size.height)];
}
#end
I went through below SO links, but didn't get solution.
LINK1 LINK2LINK3 LINK4
To be able to scroll you need to keep a view over scrollview that goes out of the bound of the screen. So drag a view and enlarge it beyong the device bounds so that it would be able to hold your subviews.
Its better to use UICollectionView for this kind of a problem. It is easier to implement and also will help you do all necessary manipulations.
Your MyCustomView is a subClass of UIScrollView. So you don't need to add UIScrollView property to your class. Delete scrollView property and replace all self.scrollView with self

Show partial content of image using animation

I am working with images in iOS. So when a user presses let's say a button, I want an image to appear to fill up from the bottom to the top.
In order be more precise, imagine a thermometer that is empty and when you press a button the thermometer fills up from the bottom to the top. But I want this with animation.
Do you have any idea how to implement that?
Thanks!
You can easily do it by having a second view acting as a mask over the image view with your image. Then you can apply simple scale transform and animate it revealing the image. Alternatively, you can animate the frame change. Effect will be the same. I'm attaching code for 2 ways of doind this.
Here is what I achieved in both cases:
Code I used for the case I:
#interface MyViewController ()
#property(nonatomic, strong) UIImageView *imageView;
#property(nonatomic, strong) UIView *maskView;
#end
#implementation MyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Image"]];
_imageView.center = self.view.center;
_imageView.layer.anchorPoint = CGPointMake(0.5, 0.0);
[self.view addSubview:_imageView];
_maskView = [[UIView alloc] initWithFrame:_imageView.frame];
_maskView.backgroundColor = [UIColor whiteColor];
_maskView.center = self.view.center;
_maskView.layer.anchorPoint = CGPointMake(0.5, 0.0);
[self.view addSubview:_maskView];
}
- (IBAction)buttonTapped:(id)sender
{
[UIView animateWithDuration:1.0f
animations:^
{
_maskView.transform = CGAffineTransformMakeScale(1.0, 0.0001);
}];
}
#end
Code I used for the case II:
#interface MyViewController ()
#property(nonatomic, strong) UIImageView *imageView;
#property(nonatomic, assign) CGFloat height;
#end
#implementation MyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Image"]];
_imageView.center = self.view.center;
_imageView.contentMode = UIViewContentModeBottom;
_height = CGRectGetHeight(_imageView.bounds);
CGRect frame = _imageView.frame;
frame.size.height = 0.00001;
frame.origin.y += _height;
_imageView.frame = frame;
_imageView.clipsToBounds = YES;
[self.view addSubview:_imageView];
}
- (IBAction)buttonTapped:(id)sender
{
[UIView animateWithDuration:1.0f
animations:^
{
CGRect frame = _imageView.frame;
frame.size.height = _height;
frame.origin.y -= _height;
_imageView.frame = frame;
}];
}
#end
In both cases the end effect was the same.
You can do this by changing the frame of the view within the animate block. For example, if myView was a 100x100 sized view:
myView.frame = CGRectMake(0, [UIScreen mainScreen].bounds.size.height, 0, 0);
[UIView animateWithDuration:1.0f
animations:^
{
myView.frame = CGRectMake(0, [UIScreen mainScreen].bounds.size.height, 100, 100);
}];
This example should enlarge a 100x100 view in the bottom left corner of the screen, making it appear to reveal itself from the bottom up.

Resources