custom UITextField: In the click TextField input,After the keyborad popup,enter the background to get enter foreground again,The app crash!
if you don't click TextField input,background or foreground conversion ,It is normal;Part of the code:
#implementatio BKSearchViewController
- (void)setNavgationView {
BKSearchBar *searchBar = [[BKSearchBar alloc] initWithFrame:CGRectMake(20, 27, kScreenWidth - 90, 30)];
searchBar.placeholder = #"输入昵称/拜托号";
searchBar.delegate = self;
[searchBar setKeyboardType:UIKeyboardTypeDefault];
[searchBar setReturnKeyType:UIReturnKeySearch];
[searchBar setPlaceholderColor:kcallColor(#"a4a4a4")];
[searchBar setPlaceholderFont:kFont(14)];
[searchBar addTarget:self action:#selector(SearchTextFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
[navgationView addSubview:searchBar];
}
#end
//BKSearchBar The key code
#implementation BKSearchBar
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// 设置背景
self.backgroundColor = kcallColor(#"7d1d57");
self.returnKeyType = UIReturnKeySearch;
// 设置内容 -- 垂直居中
self.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
[self UI];
}
return self;
}
- (void)UI{
// 设置左边显示一个放大镜
UIImageView *leftView = [[UIImageView alloc] init];
omit...
//右边的view
UIImageView *rightView = [[UIImageView alloc] init];
omit...
}
- (CGRect)placeholderRectForBounds:(CGRect)bounds{
CGRect rect = CGRectMake(self.leftView.right, (self.height - 24) / 2, bounds.size.width, 14);
return rect;
}
- (void)clearText{
self.text = nil;
}
- (void)setPlaceholderColor:(UIColor *)color{
[self setValue:color forKeyPath:#"_placeholderLabel.textColor"];
}
- (void)setPlaceholderFont:(UIFont *)font{
[self setValue:font forKeyPath:#"_placeholderLabel.font"];
}
Thank all!The problem is resolved!because of the runtime!
+ (void)swizzleInstanceMethod:(Class)class originSelector:(SEL)originSelector otherSelector:(SEL)otherSelector
{
Method otherMehtod = class_getInstanceMethod(class, otherSelector);
Method originMehtod = class_getInstanceMethod(class, originSelector);
// 交换2个方法的实现
method_exchangeImplementations(otherMehtod, originMehtod);
}
Related
I am attempting to create a view to show a list of items and prices using two UILabels in a UIView.
In my UIViewController I call my subview LineItemView and pass data, and return the UIView to the main view that will hold the subviews.
Though my view is returning empty. The strings are null.
ViewController.m
#import "LineItemView.h"
//...
#property (weak, nonatomic) IBOutlet UIView *viewCharges;
//...
- (void)viewDidLoad {
[super viewDidLoad];
[self loadData];
}
- (void) loadData {
//Here we will fill in the viewCharges view
LineItemView * view = [[LineItemView alloc]init];
view.linePrice = #"1.00";
view.lineItem = #"Something";
[self.viewCharges addSubview:view];
}
LineItemView.h
#interface LineItemView : UIView {
UILabel * lblLineItem, *lblLinePrice;
}
#property (nonatomic,strong) NSString* lineItem;
#property (nonatomic,strong) NSString* linePrice;
LineItemView.m
#define LABEL_MINIMUM_HEIGHT 32
#define VERTICAL_MARGIN 5
#define HORIZONTAL_MARGIN 10
#implementation LineItemView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self createUI];
[self updateData];
NSLog(#"\n\n\n Line Item: %# Price: %# \n\n\n", self.lineItem, self.linePrice);
}
return self;
}
-(void) createUI {
lblLineItem = [[UILabel alloc] initWithFrame:CGRectZero];
lblLineItem.backgroundColor = [UIColor greenColor];
[self addSubview:lblLineItem];
lblLinePrice = [[UILabel alloc] initWithFrame:CGRectZero];
lblLinePrice.backgroundColor = [UIColor yellowColor];
[self addSubview:lblLinePrice];
}
- (void) updateLayout {
lblLineItem.frame = CGRectMake(HORIZONTAL_MARGIN, VERTICAL_MARGIN, 300, 35);
lblLinePrice.frame = CGRectMake(lblLineItem.frame.origin.x + lblLineItem.frame.size.width + HORIZONTAL_MARGIN, VERTICAL_MARGIN, 80, 35);
}
- (void) updateData {
lblLineItem.text = self.lineItem;
lblLinePrice.text = [NSString stringWithFormat:#"%0.2f", [self.linePrice floatValue]];
}
- (void) layoutSubviews {
[super layoutSubviews];
[self updateLayout];
}
What am I doing wrong?
If I want to continue calling LineItemView, how do I ensure that it is added below the previous one and ensure the viewCharges size is readjusted to fit all the subviews?
Solution using setters:
#implementation LineItemView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self createUI];
}
return self;
}
-(void) createUI {
lblLineItem = [[UILabel alloc] initWithFrame:CGRectZero];
lblLineItem.backgroundColor = [UIColor greenColor];
[self addSubview:lblLineItem];
lblLinePrice = [[UILabel alloc] initWithFrame:CGRectZero];
lblLinePrice.backgroundColor = [UIColor yellowColor];
[self addSubview:lblLinePrice];
}
- (void) updateLayout {
lblLineItem.frame = CGRectMake(HORIZONTAL_MARGIN, VERTICAL_MARGIN, 300, 35);
lblLinePrice.frame = CGRectMake(lblLineItem.frame.origin.x + lblLineItem.frame.size.width + HORIZONTAL_MARGIN, VERTICAL_MARGIN, 80, 35);
}
- (void) layoutSubviews {
[super layoutSubviews];
[self updateLayout];
}
- (void)setLineItem:(NSSTring *)lineItem {
_lineItem = lineItem;
lblLineItem.text = self.lineItem;
}
- (void)setLinePrice:(NSNumber *)linePrice {
_linePrice = linePrice;
lblLinePrice.text = [NSString stringWithFormat:#"%0.2f", [self.linePrice floatValue]];
}
I am developing iOS App with Objective-c. Then, I am implementing customized Activity Indicator which is active while webView is loading.
The customized Activity Indicator appears when webView starts loading, however it does not disappear when webView finishes loading.
My code is following.
Could you tell me how to solve this problem?
#interface DetailViewController ()<UIWebViewDelegate>{
{
UILabel *loadingLabel;
UIActivityIndicatorView *loadingMark;
UIView *loadingContainer;
}
#property (weak, nonatomic) IBOutlet UIWebView *detailPage;
#end
#implementation DetailViewController
- (void)configureView
{
NSURL *page_url = [NSURL URLWithString:#"http://yahoo.co.jp"];
NSURLRequest *request = [NSURLRequest requestWithURL:page_url];
[_detailPage loadRequest:request];
_detailPage.delegate = self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self configureView];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)webViewDidStartLoad:(UIWebView*)webView
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[self animatingIndicator];
}
- (void)webViewDidFinishLoad:(UIWebView*)webView
{
[self stopAndRemoveIndicator];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
-(void)animatingIndicator {
loadingContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 150, 60)];
//Set Style Of Label
loadingLabel = [[UILabel alloc] init];
loadingLabel.text = #"Loading";
loadingLabel.textColor = [UIColor whiteColor];
loadingLabel.shadowColor = [UIColor blackColor];
loadingLabel.shadowOffset = CGSizeMake(1, 1);
loadingLabel.font = [UIFont boldSystemFontOfSize:17];
loadingLabel.backgroundColor = [UIColor lightGrayColor];
loadingLabel.frame = CGRectMake(20, 17, 70, 25);
[loadingContainer addSubview:loadingLabel];
//Set Style Of Mark
loadingMark = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
loadingMark.frame = CGRectMake(100, 14, 30, 30);
[loadingContainer addSubview:loadingMark];
//Set Style Of Container
loadingContainer.backgroundColor = [UIColor lightGrayColor];
[[loadingContainer layer] setCornerRadius:8.0f];
[[loadingContainer layer] setMasksToBounds:YES];
[[loadingContainer layer] setBorderWidth:0.5f];
[[loadingContainer layer] setBorderColor:[[UIColor darkGrayColor] CGColor]];
CGRect rect = self.view.frame;
loadingContainer.center = CGPointMake(rect.size.width/2, rect.size.height/2 * 0.8);
[self.view addSubview:loadingContainer];
[loadingMark startAnimating];
loadingContainer.hidden = NO;
}
-(void)stopAndRemoveIndicator {
[loadingMark stopAnimating];
loadingContainer.hidden = YES;
[loadingMark setHidden:YES];
}
You need to hide the UIKit objects in the main thread.
override func webViewDidFinishLoad(webView:UIWebView)
{
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.loadingSign.stopAnimating()
self.loadingSign.hidden = true
}
}
Update for swift 4
override func webViewDidFinishLoad(_ webView: UIWebView)
{
DispatchQueue.main.async {
self.loadingSign.stopAnimating()
self.loadingSign.hidden = true
}
}
loadingSign is UIActivity Indicator.
This is what I have done, work fine!
.h file
#property (retain, nonatomic) IBOutlet UIActivityIndicatorView *loadingSign;
.m file
-(void)webViewDidStartLoad:(UIWebView *)webView
{
[self.loadingSign startAnimating];
self.loadingSign.hidden = NO;
}
-(void)webViewDidFinishLoad:(UIWebView *)webView
{
[self.loadingSign stopAnimating];
self.loadingSign.hidden = YES;
}
I'm trying to create a class that makes a read only text field that allows the user to copy its contents. Here is my code:
CopyOnly.h
#import <UIKit/UIKit.h>
#interface CopyOnly : UITextField
#end
CopyOnly.m
#import "CopyOnly.h"
#implementation CopyOnly
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self attachTapHandler];
}
return self;
}
- (void) attachTapHandler
{
[self setUserInteractionEnabled:YES];
UIGestureRecognizer *touchy = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
[self addGestureRecognizer:touchy];
}
- (BOOL) canPerformAction: (SEL) action withSender: (id) sender
{
return (action == #selector(copy:));
}
- (void) handleTap: (UIGestureRecognizer*) recognizer
{
[self becomeFirstResponder];
UIMenuController *menu = [UIMenuController sharedMenuController];
[menu setTargetRect:self.frame inView:self.superview];
[menu setMenuVisible:YES animated:YES];
}
- (void)copy:(id)sender
{
UIPasteboard *board = [UIPasteboard generalPasteboard];
[board setString:self.text];
self.highlighted = NO;
[self resignFirstResponder];
}
- (BOOL) canBecomeFirstResponder
{
return YES;
}
#end
This works great, only the keyboard is coming up. I don't want any keyboard to come up.
I tried adding this to initWithFrame:
UIView* noKeyboard = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
self.inputView = noKeyboard;
This does not give me the result I'm expecting. Anyone know how I can do this?
Extending on my comment. This is easily accomplished using a UITextView (not UITextField) with editable property set to NO.
UITextView* tf = [[UITextView alloc] initWithFrame:CGRectMake(50, 50, 200, 50)];
tf.editable = NO;
tf.text = #"Hey this is a test!";
[self.view addSubview:tf];
Adding this to -(BOOL)canBecomeFirtResponder seemed to do the trick. Hacky, but it works.
- (BOOL) canBecomeFirstResponder
{
UIView* noKeyboard = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
self.inputView = noKeyboard;
return YES;
}
If you stuck with text field that doesn't allow editing try totally different approach. Follow instructions in this article http://nshipster.com/uimenucontroller/ to implement UILabel that supports copying.
I am making a custom control which consists of UIImageView and Label. The control behaves like a checkbox.
Here is the code:
-(instancetype) initWithTitle:(NSString *)title normalCheckBoxImage:(NSString *)normalCheckBoxImage selectedCheckBoxImage:(NSString *)selectedCheckBoxImage
{
self = [super init];
self.userInteractionEnabled = YES;
self.normalCheckBoxImageName = normalCheckBoxImage;
self.selectedCheckBoxImageName = selectedCheckBoxImage;
self.title = title;
[self setupSubViews];
[self registerGestureRecognizers];
return self;
}
-(void) registerGestureRecognizers
{
UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(checkBoxTapped:)];
singleTapGestureRecognizer.delegate = self;
singleTapGestureRecognizer.numberOfTapsRequired = 1;
[self.checkBoxImageView addGestureRecognizer:singleTapGestureRecognizer];
}
-(void) checkBoxTapped:(UITapGestureRecognizer *) recognizer
{
self.isChecked = !self.isChecked;
if(self.isChecked)
{
[self.checkBoxImageView setImage:[UIImage imageNamed:self.selectedCheckBoxImageName]];
}
else
{
[self.checkBoxImageView setImage:[UIImage imageNamed:self.normalCheckBoxImageName]];
}
}
-(void) setupSubViews
{
self.checkBoxImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:self.normalCheckBoxImageName]];
self.checkBoxImageView.frame = CGRectMake(0, 0, 50, 50);
NSLog(#"width = %f; height = %f",self.checkBoxImageView.frame.size.width,self.checkBoxImageView.frame.size.height);
[self.checkBoxImageView setUserInteractionEnabled:YES];
// The init with frame should be replaced by the NSConstraints
self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.checkBoxImageView.frame.size.width + 5, 10, 100, 20)];
self.titleLabel.text = self.title;
[self addSubview:self.checkBoxImageView];
[self addSubview:self.titleLabel];
}
I have attached gesture recognizer to the UIImageView. But for some reason it only fires when I am close to the left edge of the UIImageView. I am not sure what I am doing wrong. If I touch in the middle of the uIImageView then it does not do anything.
Here is the image:
The problem was the frame for the super view was not correct. Instead of width and height of 50 X 50 it was 50 X 20.
AZCheckBox *checkbox = [[AZCheckBox alloc] initWithTitle:#"I agree" normalCheckBoxImage:#"NormalCheckBoxImage" selectedCheckBoxImage:#"SelectedCheckBoxImage"];
checkbox.frame = CGRectMake(100, 100, 200, 50);
checkbox.delegate = self;
[self.view addSubview:checkbox];
I have a subclassed UITextView for placeholder and background image.
Here's the code
BKCUTextView.h
#import <UIKit/UIKit.h>
#interface BKCUTextView : UITextView
- (void)setPlaceholder:(NSString *)placeholder;
- (void)setPlaceholderColor:(UIColor *)placeholderColor;
- (void)setBackgroundImage:(UIImage *)img;
#end
BKCUTextView.m
#import "BKCUTextView.h"
#interface BKCUTextView()
{
NSString * _placeholder;
UIColor * _normalColor;
UIColor * _placeholderColor;
BOOL _needToShowPlaceholder;
UIImageView * _bgImageView;
}
#end
#implementation BKCUTextView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self _initEvents];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
if(_needToShowPlaceholder) { [_placeholder drawAtPoint:CGPointMake(0, 0) withFont:self.font]; }
}
- (void)setTextColor:(UIColor *)textColor
{
_normalColor = textColor;
}
- (void)setPlaceholderColor:(UIColor *)placeholderColor
{
_placeholderColor = placeholderColor;
}
- (void)setPlaceholder:(NSString *)placeholder
{
_needToShowPlaceholder = YES;
_placeholder = placeholder;
}
-(void)setBackgroundImage:(UIImage *)img
{
if(_bgImageView == nil)
{
_bgImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
[self addSubview:_bgImageView];
[self sendSubviewToBack:_bgImageView];
[self bringSubviewToFront:self];
}
[_bgImageView setImage:img];
}
- (void)_initEvents
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_textChanged:) name:UITextViewTextDidChangeNotification object:self];
}
-(void)_textChanged:(NSNotification *)noti
{
_needToShowPlaceholder = (self.text.length == 0);
if(_needToShowPlaceholder) { self.textColor = _placeholderColor; }
else { self.textColor = _normalColor; }
[self setNeedsDisplay];
}
instance
BKCUTextView * tv = [[BKCUTextView alloc] initWithFrame:CGRectMake(5, 55, 300, 50)];
[tv setBackgroundColor:[UIColor darkGrayColor]];
[tv setTextColor:[UIColor whiteColor]];
[tv setPlaceholderColor:[UIColor grayColor]];
[tv setPlaceholder:#"placeholder here!"];
[tv setBackgroundImage:[UIImage imageNamed:#"btn_coin_prs.png"]];
[self.view addSubview:tv];
[self.view bringSubviewToFront:tv];
each property - backgroundImage and placeholderText - works fine, but when I set them together, the placeholder is drawn under the backgroundImage.
How can I bring the text above the back image?
Try this method [self bringSubviewToFront:];
Hope it will help!