Subclass simple UIButton to checkbox - iphone

i am subclassing UIButton to create a simple Checkbox behavior. here is the code :
#import "RadioButton.h"
#implementation RadioButton
#synthesize isSelected;
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[self ChangeButtonState];
}
-(void)ChangeButtonState{
if (!isSelected) {
isSelected = YES;
[self setBackgroundImage:[UIImage imageNamed:#"radiobtn_on.png"] forState:UIControlStateNormal];
}
else{
isSelected = NO;
[self setBackgroundImage:[UIImage imageNamed:#"radiobtn_off.png"] forState:UIControlStateNormal];
}
}
-(id)init{
self.adjustsImageWhenHighlighted=YES;
self.alpha = 1;
[self ChangeButtonState];
isSelected = NO;
[self setBackgroundImage:[UIImage imageNamed:#"radiobtn_off.png"] forState:UIControlStateNormal];
return self;
}
- (id)initWithFrame:(CGRect)frame
{
[self setBackgroundImage:[UIImage imageNamed:#"radiobtn_off.png"] forState:UIControlStateNormal];
isSelected = NO;
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
first, when i set the class in the interface builder to a button when i launch the app i dont see anything until i hit this invisible button.
the seconed thing is the images looks dark then the original
help would be great!
thanks!

try your stuff in - (void)awakeFromNib. define this method in your subclass. When you assign your custom class in xib then this method will be called and apply your logic there.

Related

Navigationbar coloring in ViewWillAppear happens too late in iOS 10

I am facing a weird bug, that happens only on iOS 10.
I have a application with several screens, and each screen colors the navigationBar in viewWillAppear. So when you go to the next screen, it will be properly colored.
However, when testing on iOS 10 I suddenly see the following behaviour when going back to a previous screen:
When the previous screen appears the navigationBar still has the color of the previous screen and then flashes to the proper color.
It almost looks like viewWillAppear somehow behaves as viewDidAppear.
Relevant code:
ViewController:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[ViewControllerPainter paint:self withBackground:[UIColor whiteColor] andForeground:[UIColor blackColor] andIsLight:true];
}
Painter:
+ (void)paint:(UIViewController *)controller withBackground:(UIColor *)backgroundColor andForeground:(UIColor *)foregroundColor andIsLight:(bool)isLight
{
controller.navigationController.navigationBar.opaque = true;
controller.navigationController.navigationBar.translucent = false;
controller.navigationController.navigationBar.tintColor = foregroundColor;
controller.navigationController.navigationBar.barTintColor = backgroundColor;
controller.navigationController.navigationBar.backgroundColor = backgroundColor;
controller.navigationController.navigationBar.barStyle = isLight ? UIBarStyleDefault : UIBarStyleBlack;
controller.navigationController.navigationBar.titleTextAttributes = #{NSForegroundColorAttributeName: foregroundColor};
}
Is this a bug? Is there something I can do about to fix this? It's very frustrating.
Here's what changed according to the iOS 10 SDK Release Notes:
In iOS 10, UIKit has updated and unified background management for UINavigationBar, UITabBar, and UIToolbar. In particular, changes to background properties of these views (such as background or shadow images, or setting the bar style) may kick off a layout pass for the bar to resolve the new background appearance.
In particular, this means that attempts to change the background appearance of these bars inside of -[UIView layoutSubviews], -[UIView updateConstraints], -[UIViewController willLayoutSubviews], -[UIViewController didLayoutSubviews], - [UIViewController updateViewConstraints], or any other method that is called in response to layout may result in a layout loop.
So the problem seems to be that viewWillAppear is triggering the mentioned layout loop, since it's called as a result of a layout change:
The quick fix for me was overriding popViewControllerAnimated and pushViewController and updating the navigationBar background on my subclass of UINavigationController. Here's how it looks like:
override func popViewControllerAnimated(animated: Bool) -> UIViewController? {
let poppedViewController = super.popViewControllerAnimated(animated)
// Updates the navigation bar appearance
updateAppearanceForViewController(nextViewController)
return poppedViewController
}
override func pushViewController(viewController: UIViewController, animated: Bool) {
super.pushViewController(viewController, animated: animated)
// Updates the navigation bar appearance
updateAppearanceForViewController(viewController)
}
My guess is that it works because popViewControllerAnimated and pushViewController are not called by the OS as a result of a layout change, but by a touch event. So keep that in mind if you want to find another place to update your navigationBar background.
I had to fix this with:
self.navigationController.navigationBarHidden = YES;
self.navigationController.navigationBarHidden = NO;
This way you don't have to override popviewcontroller or pushviewcontroller. It's basically triggering the navigationbar to redraw.
It's still annoying how they can just push out a new version of OS that breaks something this significant.
Try using willMoveToParentViewController, gives the same effect as overriding UINavigationController methods but without the hassle.
I am posting the solution for Objective-C (subclass of UINavigationController):
#import "FUINavigationController.h"
#interface FUINavigationController ()
#end
#implementation FUINavigationController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"current: %#",[self.topViewController class]);
if ([NSStringFromClass([self.topViewController class]) isEqualToString:#"LoginVC"]) {
[self setNavBarHidden];
}
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(UIViewController*)popViewControllerAnimated:(BOOL)animated {
UIViewController *popedVC = [super popViewControllerAnimated:animated];
if ([NSStringFromClass([popedVC class]) isEqualToString:#"SignUpVC"] && [NSStringFromClass([[super topViewController] class]) isEqualToString:#"LoginVC"]) {
[self setNavBarHidden];
}
return popedVC;
}
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
[super pushViewController:viewController animated:animated];
[self setNavBarVisible];
}
-(void)setNavBarHidden {
[self.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
[self.navigationBar setShadowImage:[UIImage new]];
[self.navigationBar setTranslucent:YES];
[self.navigationBar setBackgroundColor:[UIColor clearColor]];
}
-(void)setNavBarVisible {
[self.navigationBar setBackgroundColor:[UIColor grayColor]];
[self.navigationBar setBarTintColor:[UIColor grayColor]];
[self.navigationBar setTintColor:[UIColor whiteColor]];
[self.navigationBar setTranslucent:NO];
[self.navigationBar setTitleTextAttributes:#{NSForegroundColorAttributeName :[UIColor whiteColor]}];
[self.navigationBar setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys: [UIColor whiteColor], NSForegroundColorAttributeName, [UIFont fontWithName:#"Roboto-Reqular" size:18], NSFontAttributeName,nil]];
[self.navigationBar.topItem setBackBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:#"" style:UIBarButtonItemStylePlain target:nil action:nil]];
}
#end
OR using method swizzling:
#import <objc/runtime.h>
#import "UINavigationController+FadeOutNavigationBar.h"
#implementation UINavigationController (FadeOutNavigationBar)
+(void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
//Swizzling view will appear
SEL originalSelectorVWA = #selector(viewWillAppear:);
SEL swizzledSelectorVWA = #selector(swizzled_viewWillAppear:);
Method originalMethodVWA = class_getInstanceMethod(class, originalSelectorVWA);
Method swizzledMethodVWA = class_getInstanceMethod(class, swizzledSelectorVWA);
BOOL didAddMethodVWA =
class_addMethod(class,
originalSelectorVWA,
method_getImplementation(swizzledMethodVWA),
method_getTypeEncoding(swizzledMethodVWA));
if (didAddMethodVWA) {
class_replaceMethod(class,
swizzledSelectorVWA,
method_getImplementation(originalMethodVWA),
method_getTypeEncoding(originalMethodVWA));
} else {
method_exchangeImplementations(originalMethodVWA, swizzledMethodVWA);
}
//Swizzling popViewControllerAnimated
SEL originalSelectorPVCA = #selector(popViewControllerAnimated:);
SEL swizzledSelectorPVCA = #selector(swizzled_popViewControllerAnimated:);
Method originalMethodPVCA = class_getInstanceMethod(class, originalSelectorPVCA);
Method swizzledMethodPVCA = class_getInstanceMethod(class, swizzledSelectorPVCA);
BOOL didAddMethodPVCA =
class_addMethod(class,
originalSelectorPVCA,
method_getImplementation(swizzledMethodPVCA),
method_getTypeEncoding(swizzledMethodPVCA));
if (didAddMethodPVCA) {
class_replaceMethod(class,
swizzledSelectorVWA,
method_getImplementation(originalMethodPVCA),
method_getTypeEncoding(originalMethodPVCA));
} else {
method_exchangeImplementations(originalMethodPVCA, swizzledMethodPVCA);
}
//Swizzling pushViewController
SEL originalSelectorPVC = #selector(pushViewController:animated:);
SEL swizzledSelectorPVC = #selector(swizzled_pushViewController:animated:);
Method originalMethodPVC = class_getInstanceMethod(class, originalSelectorPVC);
Method swizzledMethodPVC = class_getInstanceMethod(class, swizzledSelectorPVC);
BOOL didAddMethodPVC =
class_addMethod(class,
originalSelectorPVC,
method_getImplementation(swizzledMethodPVC),
method_getTypeEncoding(swizzledMethodPVC));
if (didAddMethodPVC) {
class_replaceMethod(class,
swizzledSelectorPVC,
method_getImplementation(originalMethodPVC),
method_getTypeEncoding(originalMethodPVC));
} else {
method_exchangeImplementations(originalMethodPVC, swizzledMethodPVC);
}
});
}
#pragma mark - Method Swizzling
- (void)swizzled_viewWillAppear:(BOOL)animated {
[self swizzled_viewWillAppear:animated];
NSLog(#"current: %#",[self.topViewController class]);
if ([NSStringFromClass([self.topViewController class]) isEqualToString:#"LoginVC"]) {
[self setNavBarHidden];
}
}
-(void)setNavBarHidden {
[self.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
[self.navigationBar setShadowImage:[UIImage new]];
[self.navigationBar setTranslucent:YES];
[self.navigationBar setBackgroundColor:[UIColor clearColor]];
}
-(void)setNavBarVisible {
[self.navigationBar setBackgroundColor:[UIColor grayColor]];
[self.navigationBar setBarTintColor:[UIColor grayColor]];
[self.navigationBar setTintColor:[UIColor whiteColor]];
[self.navigationBar setTranslucent:NO];
[self.navigationBar setTitleTextAttributes:#{NSForegroundColorAttributeName :[UIColor whiteColor]}];
[self.navigationBar setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys: [UIColor whiteColor], NSForegroundColorAttributeName, [UIFont fontWithName:#"Roboto-Reqular" size:18], NSFontAttributeName,nil]];
[self.navigationBar.topItem setBackBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:#"" style:UIBarButtonItemStylePlain target:nil action:nil]];
}
-(UIViewController*)swizzled_popViewControllerAnimated:(BOOL)animated {
UIViewController *popedVC = [self swizzled_popViewControllerAnimated:animated];
if ([NSStringFromClass([popedVC class]) isEqualToString:#"SignUpVC"] && [NSStringFromClass([[self topViewController] class]) isEqualToString:#"LoginVC"]) {
[self setNavBarHidden];
}
return popedVC;
}
-(void)swizzled_pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
[self swizzled_pushViewController:viewController animated:animated];
[self setNavBarVisible];
}
#end

Can you customize UISlider like the "unlock slider" in iPhone?

I have a question about UISliders in IOS and to what extent you can customize them?
I would like to implement a slider like the "Unlock slider" in iPhone.
But it seems like IOS have not provided any "standard" ways for implementing a slider like this?.
Is it possible to implement a standard UISlider and set it to a min.value (0.0) and maximum.value (0.5). If the slider "hits" a value greater then (0.01) it should automatically be pulled back to the min.value (0.0).
If it hits the maximum value (0.5), start an event then automatically pulled back to min.value?
All help is appreciated!
Try this. I use this in my Project
Slider.h
#class Slider;
#protocol SliderDelegate <NSObject>
#required
- (void) slideEnd;
#end
#interface Slider : UISlider
#property (nonatomic, weak) id<SliderDelegate> delegate;
Slider.m
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setMinimumTrackImage:YOUR_MINIMUM_TRACK_IMG forState:UIControlStateNormal];
[self setMaximumTrackImage:YOUR_MAXIMUM_TRACK_IMG forState:UIControlStateNormal];
[self setThumbImage:YOUR_THUMB_IMAGE];
self.minimumValue = 0.0;
self.maximumValue = 1.0;
self.value = 0.0;
[self addTarget:self action:#selector(moved:) forControlEvents:UIControlEventTouchUpInside];
[self addTarget:self action:#selector(moved:) forControlEvents:UIControlEventTouchUpOutside];
}
return self;
}
- (void) moved:(UISlider *) sender
{
if (self.value != 1.0) {
[self setValue: 0 animated: YES];
} else {
[[self delegate] slideEnd];
[self setValue: 0 animated: YES];
}
}
Implement it like this:
[self setSlider:[[Slider alloc] initWithFrame:CGRectMake(645, 25, 120, 50)]];
[[self view] addSubview:[self slider]];
[[self view] bringSubviewToFront:[self slider]];
[[self slider] setDelegate:self];
Don't forget to implement the delegate method:
- (void)slideEnd {
// Things you want to do when slide ends
}

pass #selector to my UIbutton but click event not response

my code :
- (void)showWithStatus:(NSString *)status barColor:(UIColor*)barColor textColor:(UIColor*)textColor click:(SEL)click{
if(!self.superview)
[self.overlayWindow addSubview:self];
[self.overlayWindow setHidden:NO];
[self.topBar setHidden:NO];
self.topBar.backgroundColor = barColor;
NSString *labelText = status;
CGRect labelRect = CGRectZero;
CGFloat stringWidth = 0;
CGFloat stringHeight = 0;
if(labelText) {
CGSize stringSize = [labelText sizeWithFont:self.stringLabel.font constrainedToSize:CGSizeMake(self.topBar.frame.size.width, self.topBar.frame.size.height)];
stringWidth = stringSize.width;
stringHeight = stringSize.height;
labelRect = CGRectMake((self.topBar.frame.size.width / 2) - (stringWidth / 2), 0, stringWidth, stringHeight);
}
self.stringLabel.frame = labelRect;
self.stringLabel.alpha = 0.0;
self.stringLabel.hidden = NO;
self.stringLabel.text = labelText;
self.stringLabel.textColor = textColor;
clickBn=[[UIButton alloc]initWithFrame:self.stringLabel.frame];
clickBn.backgroundColor=[UIColor blueColor];
[clickBn addTarget:self action:click forControlEvents:UIControlEventTouchUpInside];
if(!clickBn.superview)
[self.topBar addSubview:clickBn];
[UIView animateWithDuration:0.4 animations:^{
self.stringLabel.alpha = 1.0;
}];
// [self setNeedsDisplay];
}
and call this method:
- (IBAction)successButtonPressed:(id)sender {
[KGStatusBar showSuccessWithStatus:#"Successfully synced" click:#selector(clickBn)];
}
- (void)clickBn {
NSLog(#"sss");
[KGStatusBar dismiss];
}
the NSLog(#"sss") not show. i want to pass a method to UIButton of customView ,but when i click the UIbutton not respond.
Create an delegate in control in .h file before #interface and after header files.
#protocol YourControlDelegate <NSObject>
-(void) delegateMethod;
#end
in #interface
#property (nonatomic,assign) id <YourControlDelegate> yourdelegate;
in .m #synthesize the yourdelegate.
in button click action call [self.yourdelegate delegateMethod];
In your ViewController add YourControlDelegate like as follow
#interface YourVC : UIViewController <YourControlDelegate>
in .m implement the delegate method
-(void) delegateMethod
{
//you code.
}
Here when you click the button the delegateMethod in viewController will be get called.
action should be a selector method.
If you want to pass the button as an argument to the method user : for example
[button addTarget:self action:#selector(buttonClicked:)
forControlEvents:UIControlEventTouchUpInside];
-(void)buttonClicked:(UIButton *)sender
{
//your code and you can also access the button properties using sender.
}
it is preferred. If you don't want to use sender(button) exclude the :
this is your clickBn method right?
- (void)clickBn {
NSLog(#"sss");
[KGStatusBar dismiss];
}
now what you doing in action? action:click??
do like following
clickBn=[[UIButton alloc]initWithFrame:self.stringLabel.frame];
clickBn.backgroundColor=[UIColor blueColor];
[clickBn addTarget:self action:#selector(clickBn) forControlEvents:UIControlEventTouchUpInside];
If you want to call method which is in another class then do like this
first make object of that class
ViewController *dvController = [ViewController alloc] init];
after that [dvController methodName];
do this all in your clickBn method First clickBn method will be called and it will call that another class method which you wanted to call
NOTE: you need to import that class in header

create uibutton subclass

I tried to subclass UIButton to include an activity indicator, but when i use initWithFrame:(since i'm subclassing uibutton i'm not using buttonWithType:) the button doesn't display. Also how would i set the button type in this case?:
my view controller:
ActivityIndicatorButton *button = [[ActivityIndicatorButton alloc] initWithFrame:CGRectMake(10, 10, 300, 44)];
[button addTarget:self action:#selector(buttonPressed) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"Older Posts..." forState: UIControlStateNormal];
[cell addSubview:button];
[button release];
my activityindicatorbutton class:
#import <Foundation/Foundation.h>
#interface ActivityIndicatorButton : UIButton {
UIActivityIndicatorView *_activityView;
}
-(void)startAnimating;
-(void)stopAnimating;
#end
#implementation ActivityIndicatorButton
- (id)initWithFrame:(CGRect)frame {
if (self=[super initWithFrame:frame]) {
_activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
_activityView.frame = CGRectOffset(_activityView.frame, 60.0f, 10.0f);
[self addSubview: _activityView];
}
return self;
}
-(void) dealloc{
[super dealloc];
[_activityView release];
_activityView = nil;
}
-(void)startAnimating {
[_activityView startAnimating];
}
-(void)stopAnimating {
[_activityView stopAnimating];
}
#end
Favour composition over inheritance.
Create a UIView which contains the components you need and add them to your view.
I ran into a similar situation, and agree with Jeff that you don't really need to subclass UIButton. I solved this by subclassing UIControl, and then overriding layoutSubviews to do all of the configuration of the views I wanted on my "button". It's a much more simple implementation that subclassing UIButton since there does seem to be some hidden mojo going on under the hood. My implementation looked like this:
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.opaque = YES;
self.imageView = [[UIImageView alloc] initWithFrame:CGRectZero];
[self addSubview:self.imageView];
self.textLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[self addSubview:self.textLabel];
}
return self;
}
And layoutSubviews looked like this:
- (void)layoutSubviews {
[super layoutSubviews];
// Get the size of the button
CGRect bounds = self.bounds;
// Configure the subviews of the "button"
...
}
I have created a custom class, preferring composition over inheritance and it works perfect. My custom class has a button and it knows it's MCContact object. Also it draws a proper button and calculates frames automatically using MCContact object, that is passed.
Header file sample:
#import <UIKit/UIKit.h>
#protocol MCContactViewDelegate;
#interface MCContactView : UIView
{
}
#property (nonatomic, strong) MCContact *mcContact;
#property (nonatomic, weak) id <MCContactViewDelegate> delegate;
- (id)initWithContact:(MCContact*)mcContact delegate:(id <MCContactViewDelegate>)delegate;
#end
#protocol MCContactViewDelegate <NSObject>
- (void)contactViewButtonClicked:(MCContactView*)contactView;
#end
Implementation file:
#import "MCContactView.h"
#interface MCContactView()
{
UIButton *_button;
}
#end
#implementation MCContactView
- (id)initWithContact:(MCContact*)mcContact delegate:(id <MCContactViewDelegate>)delegate
{
self = [super initWithFrame:CGRectZero];
if (self) {
GetTheme();
_mcContact = mcContact;
_delegate = delegate;
_button = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *normalBackgroundImage = [[UIImage imageNamed:#"tokenNormal.png"] stretchableImageWithLeftCapWidth:12.5 topCapHeight:12.5];
[_button setBackgroundImage:normalBackgroundImage forState:UIControlStateNormal];
UIImage *highlightedBackgroundImage = [[UIImage imageNamed:#"tokenHighlighted.png"] stretchableImageWithLeftCapWidth:12.5 topCapHeight:12.5];
[_button setBackgroundImage:highlightedBackgroundImage forState:UIControlStateHighlighted];
_button.titleLabel.font = [theme contactButtonFont];
[_button setTitleColor:[theme contactButtonTextColor] forState:UIControlStateNormal];
[_button setTitleEdgeInsets:UIEdgeInsetsMake(4, 6, 4, 6)];
NSString *tokenString = ([allTrim(mcContact.name) length]>0) ? mcContact.name : mcContact.eMail;
[_button setTitle:tokenString forState:UIControlStateNormal];
[_button addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
CGSize size = [tokenString sizeWithFont:[theme contactButtonFont]];
size.width += 20;
if (size.width > 200) {
size.width = 200;
}
size.height = normalBackgroundImage.size.height;
[_button setFrame:CGRectMake(0, 0, size.width, size.height)];
self.frame = _button.frame;
[self addSubview:_button];
}
return self;
}
- (void)buttonClicked:(id)sender
{
[self.delegate contactViewButtonClicked:self];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
You have a pretty obvious problem that concerns your dealloc method: [super dealloc]; must be called AT THE END of your implementation, or else the line after that will try to access a memory space (the ivar space) that has been already deallocated, so it's going to crash.
For the other problem, I'm not sure it's a good idea to put an activity monitor as the subview of a button in general...
You don’t really want to subclass UIButton. It’s a class cluster, so individual instances will be something like UIRoundRectButton or some other private Apple class. What are you trying to do that requires a subclass?

Iphone UIButton not working in nested UIViews

This is so damn simple im sure! Im missing something and im exhausted from trying to fix it. hopefully someone can help.
The Button in CharacterView.m works but the button nested down in CharacterMale.m does not. I'm not using IB everything is done progmatically.
What would cause one button to work and other not?
/////////////////////////////////////////////////////////////////////////////////
CharacterController.m
/////////////////////////////////////////////////////////////////////////////////
#import "CharacterController.h"
#import "CharacterView.h"
#implementation CharacterController
- (id)init {
NSLog(#"CharacterController init");
self = [ super init ];
if (self != nil) {
}
return self;
}
- (void)loadView {
[ super loadView ];
characterView = [ [ CharacterView alloc ] init];
self.view = characterView;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)dealloc {
[super dealloc];
}
#end
/////////////////////////////////////////////////////////////////////////////////
CharacterView.m
/////////////////////////////////////////////////////////////////////////////////
#import "CharacterView.h"
#import "CharacterMale.h"
#implementation CharacterView
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
characterMale = [ [ CharacterMale alloc ] init];
[self addSubview: characterMale];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, 200, 200, 100);
[button setImage:[UIImage imageNamed:#"btnCharSelect.png"] forState:UIControlStateNormal];
[button addTarget:self action:#selector(ApplyImage:) forControlEvents:UIControlEventTouchUpInside];
[ self addSubview: button ];
}
return self;
}
- (void)drawRect:(CGRect)rect {
}
-(void)ApplyImage:(id)sender
{
NSLog(#"CharacterView button works");
}
- (void)dealloc {
[super dealloc];
}
#end
/////////////////////////////////////////////////////////////////////////////////
CharacterMale.m
/////////////////////////////////////////////////////////////////////////////////
#import "CharacterMale.h"
#import "CharacterController.h"
#implementation CharacterMale
- (id)init {
self = [ super init];
if (self != nil) {
UIImage *image = [UIImage imageNamed:#"charMale.png"];
imageView = [[ UIImageView alloc] initWithImage:image];
[image release];
[ self addSubview: imageView ];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, 0, 200, 100);
[button setImage:[UIImage imageNamed:#"btnCharSelect.png"] forState:UIControlStateNormal];
[button addTarget:self action:#selector(ApplyImage:) forControlEvents:UIControlEventTouchUpInside];
[ self addSubview: button ];
}
return self;
}
-(void)ApplyImage:(id)sender
{
NSLog(#"CharacterMal button works");
}
- (void)dealloc {
[super dealloc];
}
#end
FINALLY!!!!!!
I had to init all the views with initWithFrame and pass in valid frame rects. Init should be used with controllers and initWithFrame passing rects for UIViews!!!!
characterView = [ [ CharacterView alloc ] initWithFrame:CGRectMake(0, 0, 480, 320)];
then
characterMale = [ [ CharacterMale alloc ] initWithFrame:frame];
Another thing to consider is that UIButton subviews that have been added a UIImageView don't work at all. You need to create a UIView that you add both the image view and the buttons to.
This is probably because interaction is turned off by default on image views, but I've not checked this.
Does the new view accept user interaction? In other words, is userInteractionEnabled enabled on the view "Characters"?
I had a similar issue when tried to add the button during the initialization of an UIView with a frame of CGRectZero:
#implementation SomeView
...
- (id)initWithTitleImage:(UIImage *) newTitleImage {
// BROKEN: frame with CGRectZero.
self = [super initWithFrame:CGRectZero];
if (self) {
UIButton *someButton = ...;
[self addSubview someButton];
}
}
Once I changed the frame to a proper rectangle, the button worked:
#implementation SomeView
...
- (id)initWithTitleImage:(UIImage *) newTitleImage {
// WORKING: frame with proper CGRect.
self = [super initWithFrame:CGRectMake(0, 0, 480, 320)];
if (self) {
UIButton *someButton = ...;
[self addSubview someButton];
}
}
I have had luck with a selector for a UIButton created in drawRect by using UIControlEventTouchDown instead of the popular UIControlEventTouchUpInside.
For me the issue was caused because, the origin of the button frame was bigger then the parent frame.