in Objc ,how to do it elegantly? - ios

I wrote a subclass of UITextView ,to make the textView auto grow or shrink with the textView's content . Now ,I have to the textView's delegate to the subclass object it self (because i have to do something in - (void)textViewDidChange:(UITextView *)textView)
#implementation AutoGrowTextViewV2
- (instancetype) initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
self.delegate = self;
}
return self;
}
- (CGSize)intrinsicContentSize
{
return [self sizeThatFits:CGSizeMake(self.bounds.size.width, MAXFLOAT)];
}
- (void)textViewDidChange:(UITextView *)textView
{
[self invalidateIntrinsicContentSize];
[self layoutIfNeeded];
}
But in practice , AutoGrowTextViewV2 always need to set it's delegate to other objects , so I had to write textViewDidChange codes in everywhere. how can i make this simple? maybe runtime forward or something?

Related

iOS Layout custom view create with xib when resized

I created MyCustomView which has two labels. One at left and one with right align and at right. It has about 30px height (it's not important). I connect it to xib and it works. In .xib I set main view width to 400px and set autolayout constraints for labels.
Now the problem. When I added to my controller in IB with UIView and set class to MyCustomView I see left label but right label is out of screen. I set constraints right but It doesn't work. When I tried to resize MyCustomView in .xib by mouse and moving with edges it's okay but when I set width value "manually" in right column it doesn't layout right (it doesn't change at all). Where is the problem? How can I fix this?
#implementation MyCustomView
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self commonInit];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self commonInit];
}
return self;
}
- (void)commonInit
{
self.backgroundColor = [UIColor clearColor];
self.view = [[[NSBundle mainBundle] loadNibNamed:#"MyCustomView"
owner:self
options:nil] firstObject];
[self addSubview:self.view];
//self.translatesAutoresizingMaskIntoConstraints = NO;
}
- (void)awakeFromNib {
[super awakeFromNib];
//[self setNeedsUpdateConstraints];
//[self setNeedsLayout];
}
#end
As you can see in comments I tried some ways but nothing helped.
New File --> iOS (Source) -- Cocoa Touch --> Next
Enter Name
Add code in MyCustomView.m
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
//self.view.backgroundColor = [UIColor redColor];
self.preferredContentSize = CGSizeMake(30.0, 400.0);
}
return self;
}

Which init method for UIView will be called when using drag and drop in xib file

here is the custom collection view,and below label is the (rating view i design).
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self initGrayStarView];
[self initYellowStarView];
[self initRatingLabel];
}
return self;
}
but i find that it every time the rating view didn't appear(image view and label did). then i found it's because that i didn't call the init method for rating view,so it's nil ,but why?
this is the init method.
but it never call it ,it only call the layoutSubview method.
Consider this sort of pattern...
-(id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self _setup];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aCoder {
if (self = [super initWithCoder:aCoder]) {
[self _setup];
}
return self;
}
-(void)_setup {
blah;
blah;
blah;
}
Try to "know what is happening" but that will get you through if you're just getting started. Hope it helps
It is in the awakeFromNib: method. Override it in your implementation file like this:
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
[self setupStuff];
}

Subclassing UITextField

I'd like to create a text field which uses the number pad and accepts only numbers, even when pasted. Currently, I have a header as such:
#import <UIKit/UIKit.h>
#interface DRPNumberTextField : UITextField <UITextFieldDelegate>
#end
and an implementation:
#import "DRPNumberTextField.h"
#implementation DRPNumberTextField
- (id) initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.delegate = self;
[self setKeyboardType:UIKeyboardTypeNumberPad];
}
return self;
}
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if ([string rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location != NSNotFound)
{
return NO;
}
return YES;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
I've set the text fields to use this class in the storyboard. However, my desired functionality does not occur. Moreover, as determined by debugging, initWithFrame: is never called. Any ideas? As more context, these text fields are embedded inside table cells of a table view of a table view controller. Of these, I provide a custom implementation of the table view controller here:
#interface DRPImplementSettingsViewController ()
#end
#implementation DRPImplementSettingsViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
Thus it really has no implemented functionality beyond the stock. Its header is the obvious one.
EDIT: As some have pointed out, I don't need to subclass the text field to implement delegate functionality. I can put that elsewhere. But my question is this: why doesn't what I've presented here work? I can't find my mistake.
You need also override - (id)initWithCoder:(NSCoder *)decoder in your DRPNumberTextField. if you are using the custom UITextField in XIB or storyboard, initWithFrame: will not be called, initWithCoder: is called instead.
You can try with this also,
Its also works
DRPNumberTextField.m
#import "DRPNumberTextField.h"
#implementation DRPNumberTextField
- (void)awakeFromNib
{
[super awakeFromNib];
self.delegate = self;
[self setKeyboardType:UIKeyboardTypeNumberPad];
}
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if ([string rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location != NSNotFound)
{
return NO;
}
return YES;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
You don't need to subclass to do this, you can just implement theUITextFieldDelegate method textField:shouldChangeCharactersInRange:replacementString:. Every time the method is called check that the replacementString only contains characters you want to allow and return YES or NO depending on whether it does.
Here is an alternative to subclassing, rather subclassing you can use delegate method of textfield for that
check this,
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
#define NUMBERS #"0123456789"
#define NUMBERSPERIOD #"0123456789-"
NSCharacterSet *cs;
NSString *filtered;
// Period is in use
if (textField.tag==8)
{
cs = [[NSCharacterSet characterSetWithCharactersInString:NUMBERS] invertedSet];
filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
return [string isEqualToString:filtered];
}
return YES;
}
Set your textfield tag appropriate . It will also want past other character.

FusionCharts on iOS: Invisible second chart

I'm using FusionCharts on an iOS application.
Currently I have a view controller with two different UIWebViews that are loading two different charts from different html files.
The problem is that both charts are rendered but one of them is invisible as you can see in the screenshot.
It only works with one chart at a time. How can I fix this?!
screenshot
The problem this issue is is with UIWebView it self for clear explanation check out below link
http://double-slash.net/2010/10/18/using-multiple-ios-uiwebview-objects/ It can be fixed in two way by adopting a spin lock mechanism or increasing rendering time of run loop by customize the UIWebview.
enter code here
#interface FCXTCustomWebView ()
#property (assign) id idelegate;
#end
#implementation FCXTCustomWebView
- (id)init
{
self = [super init];
if (self)
{
self.delegate = self;
}
return self;
}
- (id) initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
self.delegate = self;
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.delegate = self;
}
return self;
}
- (void)setDelegate:(id<UIWebViewDelegate>)delegate
{
_idelegate = delegate;
}
- (void)stopRunLoop
{
CFRunLoopRef runLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
CFRunLoopStop(runLoop);
}
- (void) webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
[self performSelector:#selector(stopRunLoop) withObject:nil afterDelay:.01];
if ([_idelegate respondsToSelector:#selector(webView:didFailLoadWithError:)])
{
[_idelegate webView:webView didFailLoadWithError:error];
}
}
- (BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
if ([_idelegate respondsToSelector:#selector(webView:shouldStartLoadWithRequest:navigationType:)])
{
return [_idelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
}
else
{
return YES;
}
}
- (void) webViewDidFinishLoad:(UIWebView *)webView
{
[self performSelector:#selector(stopRunLoop) withObject:nil afterDelay:.01];
if ([_idelegate respondsToSelector:#selector(webViewDidFinishLoad:)])
{
[_idelegate webViewDidFinishLoad:webView];
}
}
- (void) webViewDidStartLoad:(UIWebView *)webView
{
[self performSelector:#selector(stopRunLoop) withObject:nil afterDelay:.1];
if ([_idelegate respondsToSelector:#selector(stopRunLoop)])
{
[_idelegate webViewDidStartLoad:webView];
}
}
- (void) loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL
{
[super loadHTMLString:string baseURL:baseURL];
CFRunLoopRunInMode((CFStringRef)NSDefaultRunLoopMode, 1.5, NO);
}
#end
This reply might be too late. I encountered the same issue with HighCharts.
You need not subclass UIWebView. You need to have different Javascript files for the each graph. That would work.

Subclassing a UIView, one method to setup whether initWithFrame: or awakeFromNib

When subclassing a UIView I tend to create a private method called 'setup', which I put into initWithFrame and awakeFromNib.
Is this what other people tend to do too? Or is there a method I don't know about that does what I'm looking to do.
I've been through the UIView class reference but I can't see anything, so just wondered what others do?
I actually avoid using -awakeFromNib and use -initWithCoder: instead. This is my typical UIView subclass setup:
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self _init];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self _init];
}
return self;
}
- (id)init {
if (self = [super init]) {
[self _init];
}
return self;
}
- (void)_init {
}
I actually have a Snippet to do this too. I just type
init_view
And it generates all of the above.

Resources