Is it possible to allow user input text on a UIImageView, just like the text tool in painter?
I cannot find any resource on this topic?
UIImageView is not designed to hold any text, but you could add a UILabel or UITextField either within it or on top / below it, depending on what you want to do.
For example, suppose you want to allow the user to edit a piece of text inside an image. You could do something like this:
UIImage* image = [UIImage imageNamed:#"my_image.png"];
UIImageView* imageView = [[UIImageView alloc] initWithImage:image];
imageView.userInteractionEnabled = YES;
UITextField* textField = [[UITextField alloc]
initWithFrame:CGRectMake(10, 10, 50, 20)];
textField.placeholder = #"type here";
[imageView addSubview:textField];
// You might also want to set the imageView's frame.
[self.view addSubview:imageView];
If you add a UITextField as a subview of a UIImageView, it's important to set the userInteractionEnabled to YES, since it defaults to NO for that superview (it's usually YES by default in most UIViews).
Addendum
If you want the user to be able to click anywhere in the image to edit the text, here is one way to do it: subclass UIControl and add a UIImageView and a UITextField as subviews of it, and connect the clicking action of the UIControl to the UITextField. Something like this (WARNING: not tested code, but it conveys the general idea):
#interface ImageAndTextView : UIControl {
UIImageView* imageView;
UITextField* textField;
}
#property (nonatomic, retain) UIImageView* imageView;
#property (nonatomic, retain) UITextField* textField;
- (void) click;
#end
#implementation ImageAndTextView
#synthesize imageView, textField;
- (id) initWithFrame: (CGRect) frame_ {
if (self = [super initWithFrame:frame_]) {
UIImage* image = [UIImage imageNamed:#"my_image.png"];
self.imageView = [[[UIImageView alloc] initWithImage:image] autorelease];
imageView.userInteractionEnabled = YES;
[self addSubview:imageView];
CGRect textFrame = CGRectMake(10, 10, 50, 20); // whatever frame you want
self.textField = [[[UITextField alloc]
initWithFrame:textFrame] autorelease];
[self addSubview:textField];
// Now register an event to happen if the user clicks anywhere.
[self addTarget:self action:#selector(click)
forEvent:UIControlEventTouchUpInside];
}
return self;
}
- (void) click {
[textField becomeFirstResponder];
}
#end
This is not possible with the current iPhone API (3.1). You will need to create your own custom uitextfields and your own image rendering methods to combine the layers into a captioned photo.
Related
I have made a simple subclass of UIView which has a few subviews but its breaking for a reason I can't see.
In my storyboard view controller I have added a UIView and made it the shape I want it, and added my custom class to it. The contents of my subclass is below:
#implementation PersonDetailCell
#synthesize button, requiredMarker, textField;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
-(void)layoutSubviews
{
[self setBackgroundColor:[UIColor colorWithRed:87.0f/255.0f green:153.0f/255.0f blue:191.0f/255.0f alpha:1.0f]];
textField = [[DetailTextField alloc] initWithFrame:CGRectMake(10, 0, self.frame.size.width -20, self.frame.size.height)];
[textField setFont:[UIFont fontWithName:#"Helvetica" size:14.0f]];
[textField setTextColor:[UIColor whiteColor]];
[textField setHidden:YES];
[self addSubview:textField];
button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[button setHidden:YES];
[self addSubview:button];
requiredMarker = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 4, 22)];
[requiredMarker setBackgroundColor:[UIColor redColor]];
[requiredMarker setHidden:YES];
[self addSubview:requiredMarker];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
Then in my view controller code I have imported my subclass and hooked up an IBOutlet of it to my view in my storyboard. In my viewDidLoad of my view controller I also try setting background colour of this view but nothing happens.
All of my code runs without crashing, but my issues:
I can't set the background colour from my view controller, (or any other properties for that matter).
When I run the app, the height is more than that I set in my storyboard (width is fine), but I change the height of the view nowhere.
Any ideas? Am i using the wrong approach somehow?
Thanks.
If it is a table cell, then the class should be extending UITableViewCell. Buttons and textfields can be added on the storyboard - then you can use struts and springs (Size Inspector pane) to ensure the view resizes properly. I don't think layoutSubviews should be used for adding new UI elements (maybe for resizing if you need to do it manually).
Here is some working code:
#interface ChildView()
#property (strong, nonatomic) UITextField *textField;
#property (strong, nonatomic) UIButton *button;
#property (strong, nonatomic) UIImageView *requiredMarker;
#end
#implementation ChildView
#synthesize textField= _textField;
#synthesize button = _button;
#synthesize requiredMarker = _requiredMarker;
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self setBackgroundColor:[UIColor colorWithRed:87.0f/255.0f green:153.0f/255.0f blue:191.0f/255.0f alpha:1.0f]];
self.textField = [[UITextField alloc] init];
[self.textField setFont:[UIFont fontWithName:#"Helvetica" size:14.0f]];
[self.textField setTextColor:[UIColor whiteColor]];
self.textField.text = #"Test text";
[self addSubview:self.textField];
self.button = [[UIButton alloc] init];
self.button.backgroundColor = [UIColor greenColor];
[self addSubview:self.button];
self.requiredMarker = [[UIImageView alloc] init];
[self.requiredMarker setBackgroundColor:[UIColor redColor]];
[self addSubview:self.requiredMarker];
}
return self;
}
-(void)layoutSubviews
{
CGSize hostSize = self.frame.size;
float length = 22;
self.textField.frame = CGRectMake(10, length, hostSize.width, hostSize.height-length);
self.button.frame = CGRectMake(0, 0, hostSize.width, length);
self.requiredMarker.frame = CGRectMake(0, 0, 4, length);
}
#end
I try to make a cool news app like BBC news. I think each news item (see picture) must have a UIImage and UILabel (title of news) inside it --> We must create custom view.
I adready have read how to create custom view in Apple Developer website but it only introduces, not has some samples.
My question is:
+ How can I create that customview (a UIImage with a UILabel inside)
+ How can I put that view in tableview in my main screen app.
Thank in advance. Sorry for poor English.
You can accomplish this task in many ways
1.You can create a Custom View with UIImageView and UILabel and add it as subview in tableViewCell
2.You can create Custom TableViewCell with the required labels and UIImageView and use it directly.
To create Custom View with UIImageView and UILabel
Right click "project" -> Choose "New File" -> Select "Objective C Class"-> Select "Subclass of UIView"
CustomView.h
#interface CustomView : UIView
{
}
- (id)initWithFrame:(CGRect)frame withImage:(UIImage *)img withLabel:(NSString *)lbl ;
#end
CustomView.m
#implementation CustomView
- (id)initWithFrame:(CGRect)frame withImage:(UIImage *)img withLabel:(NSString *)lbl
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
UIImageView * imageView1 = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height - 30)];
[imageView1 setImage:img];
[self addSubview:imageView1];
[imageView1 release];
UILabel * label1 = [[UILabel alloc] initWithFrame:CGRectMake(0, frame.size.height - 30, frame.size.width,30)];
label1.text = lbl;
label1.textColor = [UIColor blackColor];
[self addSubview:label1];
[label1 release];
}
return self;
}
#end
To use it
Import CustomView using #import "CustomView.h" and
CustomView * cView = [[CustomView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) withImage:[UIImage imageNamed:#"img.png"] withLabel:#"Testasddddddddddddd"];
[self.view addSubview:cView];
[cView release];
Try this..
UIButton *objBtn;
objBtn = [[UIButton alloc] init];
objBtn.frame = CGRectMake(x, y, W, H);
[objBtn setBackgroundImage:[UIImage imageNamed:#"defalt_person_01.png"] forState:UIControlStateNormal];
[objBtn addTarget:self action:#selector(SelectLanguageBtn:) forControlEvents:UIControlEventTouchUpInside];
objBtn.tag = 101;
[self.view addSubview:objBtn];
//Your News On Imagebtn
UILabel *newsLab=[[UILabel alloc]initWithFrame:CGRectMake(BtnX, BtnY, W, H)];
newsLab.textAlignment=UITextAlignmentCenter;
newsLab.textColor=[UIColor orangeColor];
newsLab.backgroundColor=[UIColor clearColor];
newsLab.text = #"My News";
newsLab.font=[UIFont fontWithName:#"TimesNewRomanPS-BoldMT" size:30];
[objBtn addSubview:newsLab];
Apart from #Shaheen M Basheer answer u can also try MGBox2 open source library which helps you to create Custom UIViews and arrange them in different Layout,also checkout sample given with it.It also support Grid layout which you can use to get what u intend.
How to achieve below effect??
I want that when my UIImage width is smaller then UILabel width then my image should be displayed only once as below.
I already have done some more work with UILabel and UIImage. Refer to my previous question : How to stretch Image to fill the Label Width set in Background in UILabel?.
But now i want some more fun with UILabel... :D
EDIT :
SBLabel *lbl = [[SBLabel alloc] initWithFrame:CGRectMake(0, 50, 320, 28)];
lbl.text = #"Hello World!!!...";
UIImage *img = [UIImage imageNamed:#"cn3.png"];
UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 50, 320, 28)];
imgView.image = img;
[lbl setNonRepeatingBackgroundImage:imgView];
[self.view addSubview:lbl];
[imgView release];
if (image.size.width < label.size.width ||image.size.height < label.size.height )
{
//rect here is frame of image
[img drawInRect:rect];
label.backgroudColor = [UIColor clearColor];
}
It seems like the most straightforward solution would be to have your UIImage sit behind your UILabel and your UILabel has a transparent background color.
Edit
Assuming you're using ARC...
SBLabel.h
#import <UIKit/UIKit.h>
#interface SBLabel : UILabel
#property (nonatomic, strong) UIImageView *nonRepeatingBackgroundImage;
#end
SBLabel.m
#import "SBLabel.h"
#implementation SBLabel
#synthesize nonRepeatingBackgroundImage;
- (void)setNonRepeatingBackgroundImage:(UIImageView *)aNonRepeatingBackgroundImage {
nonRepeatingBackgroundImage = aNonRepeatingBackgroundImage;
[self addSubview:aNonRepeatingBackgroundImage];
[self sendSubviewToBack:aNonRepeatingBackgroundImage];
[self setBackgroundColor:[UIColor clearColor]];
}
#end
You would need to call this setter method after you add the UILabel to the parent view. I have not tested but I believe it should work, might require some tweaks but hopefully it explains how to Subclass UILabel to make a custom enhancement such as this.
A subclass of UILabel could look like this (without ARC)
CustomLabel.h
#import <UIKit/UIKit.h>
#interface CustomLabel : UILabel {
UIImage *mImage;
}
#property (retain) UIImage *image;
#end
CustomLabel.m
#import "CustomLabel.h"
#implementation CustomLabel
- (void)dealloc {
self.image = nil;
[super dealloc];
}
- (void)drawRect:(CGRect)rect {
[mImage drawAtPoint:CGPointMake(0, 0)];
[super drawRect:rect];
}
- (UIImage*)image {
return mImage;
}
- (void)setImage:(UIImage *)image {
self.backgroundColor = [UIColor clearColor];
if(mImage)
[mImage release];
mImage = [image retain];
[self setNeedsDisplay];
}
#end
Usage
yourCustomLabel.image = [UIImage imageNamed:#"test.png"];
In my project i'm using a UITextField which is embedded into a plain white UIButton with rounded corners in order to create a "beautiful" text field. This code is used several times in different views so I decided to create a custom UIView for this purpose. The code for this custom UIView:
BSCustomTextField.h
#import <Foundation/Foundation.h>
#interface BSCustomTextField : UIView {
UIButton* btnTextFieldContainer;
UITextField* textField;
NSString* text;
}
#property (retain, nonatomic) UIButton* btnTextFieldContainer;
#property (retain, nonatomic) UITextField* textField;
#property (retain, nonatomic) NSString* text;
-(id)initWithPosition:(CGPoint)position;
#end
BSCustomTextField.m
#import "BSCustomTextField.h"
#import <QuartzCore/QuartzCore.h>
#implementation BSCustomTextField
#synthesize btnTextFieldContainer, textField, text;
-(id)initWithPosition:(CGPoint)position{
if (self == [super init]) {
btnTextFieldContainer = [[UIButton alloc] initWithFrame:CGRectMake(position.x, position.y, 260, 50)];
btnTextFieldContainer.backgroundColor = [UIColor whiteColor];
[[btnTextFieldContainer layer] setCornerRadius:3.];
[[btnTextFieldContainer layer] setMasksToBounds:YES];
[[btnTextFieldContainer layer] setBorderWidth:0.];
textField = [[UITextField alloc] initWithFrame:CGRectMake(10, 10, 240, 30)];
textField.backgroundColor = [UIColor whiteColor];
textField.clearButtonMode = UITextFieldViewModeAlways;
textField.returnKeyType = UIReturnKeySend;
textField.keyboardType = UIKeyboardTypeEmailAddress;
textField.font = [UIFont fontWithName:#"Helvetica-Bold" size:20.];
[btnTextFieldContainer addSubview:textField];
[self addSubview:btnTextFieldContainer];
}
return self;
}
-(void)dealloc{
[btnTextFieldContainer release];
[textField release];
[super dealloc];
}
#end
So, when using this view in the viewDidLoad of the container view (see code below) the view is properly rendered on the desired position and looks exactly as specified but it does not react on touch events and thus does not become first responder when touched.
Code:
searchTextField = [[BSCustomTextField alloc] initWithPosition:CGPointMake(30, 150)];
searchTextField.textField.placeholder = NSLocalizedString(#"lsUserName", #"");
[[(BSPlainHeaderWithBackButtonView*)self.view contentView] addSubview:searchTextField];
Calling [searchTextField.textField becomeFirstResponder] programmatically works properly and makes the keyboard to appear.
But, the interesting part is, if I embed the code of BSCustomTextField inline in my container just like this:
UIButton* btnTextFieldContainer = [[UIButton alloc] initWithFrame:CGRectMake(30, 150, 260, 50)];
btnTextFieldContainer.backgroundColor = [UIColor whiteColor];
[[btnTextFieldContainer layer] setCornerRadius:3.];
[[btnTextFieldContainer layer] setMasksToBounds:YES];
[[btnTextFieldContainer layer] setBorderWidth:0.];
searchTextField = [[UITextField alloc] initWithFrame:CGRectMake(10, 10, 240, 30)];
searchTextField.backgroundColor = [UIColor whiteColor];
searchTextField.clearButtonMode = UITextFieldViewModeAlways;
searchTextField.returnKeyType = UIReturnKeySend;
searchTextField.keyboardType = UIKeyboardTypeEmailAddress;
searchTextField.font = [UIFont fontWithName:#"Helvetica-Bold" size:20.];
searchTextField.placeholder = NSLocalizedString(#"lsUserName", #"");
[btnTextFieldContainer addSubview:searchTextField];
[[(BSPlainHeaderWithBackButtonView*)self.view contentView] addSubview:btnTextFieldContainer];
[btnTextFieldContainer release];
everything works as expected and the textfield reacts on touches. The type of the searchTextField is properly set in the header file for each case. The only difference is that in the first case I have an additional wrapping UIView on the UIButton and the UITextFiled. I have no idea what to do to make the text field to become first responder on touch.
Thanks a lot in advance,
Roman
Ok, I've got the solution. raaz's point to the UIResponder class tipped me off to the idea that there must be something wrong in the responder chain, thus I did a little research and found this topic: Allowing interaction with a UIView under another UIView in which exact the same problem is discussed.
Here is the new working code for BSCustomTextField.m
#import "BSCustomTextField.h"
#import <QuartzCore/QuartzCore.h>
#implementation BSCustomTextField
#synthesize btnTextFieldContainer, textField, text;
-(id)initWithPosition:(CGPoint)position{
if (self == [super init]) {
btnTextFieldContainer = [[UIButton alloc] initWithFrame:CGRectMake(position.x, position.y, 260, 50)];
btnTextFieldContainer.backgroundColor = [UIColor whiteColor];
[[btnTextFieldContainer layer] setCornerRadius:3.];
[[btnTextFieldContainer layer] setMasksToBounds:YES];
[[btnTextFieldContainer layer] setBorderWidth:0.];
textField = [[UITextField alloc] initWithFrame:CGRectMake(10, 10, 240, 30)];
textField.backgroundColor = [UIColor whiteColor];
textField.clearButtonMode = UITextFieldViewModeAlways;
textField.returnKeyType = UIReturnKeySend;
textField.keyboardType = UIKeyboardTypeEmailAddress;
textField.font = [UIFont fontWithName:#"Helvetica-Bold" size:20.];
[btnTextFieldContainer addSubview:textField];
[self addSubview:btnTextFieldContainer];
}
return self;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
// UIView will be "transparent" for touch events if we return NO
return YES;
}
-(void)dealloc{
[btnTextFieldContainer release];
[textField release];
[super dealloc];
}
#end
Since the clickable area fills out the entire BSCustomTextField view we can simply return YES in pointInside:withEvent:
Thank you all for pointing me into the right direction.
Refer UIResponder class
This class has instance method becomeFirstResponder: & isFirstResponder:
Also do not forget to set textfield editing property to YES
Oh, you're completely wrong with doing this way. You should add stretchable image into UIImageView and put it below UITextField.
UIImage *backgroundImage = [[UIImage imageNamed:#"fieldBackground.png"] stretchableImageWithLeftCapWidth:12.0 topCapHeight:0.0];
Or you can try to disable userInteraction in UIButton.
What I Want: A border indicating if a UIButton is selected or not.
Background: I've got some UIButtons using transparent images, not text. These are toggle buttons (i.e. can be on or off).
Problem: The UIButton class gives users no indication of whether a button is selected or not unless you change something else about the button. Since the image doesn't change with the state, I'd need two of every image, one normal, one selected and set one for each state of the button. This is annoying. I thought instead I'd change the background image, but this removes the pretty border on the button, I just get a rectangle of my background image, yuck.
Possible solutions I don't like:
1) Create a background that matches the UIButton border and use that for selected. I don't like this because they wont match perfectly and I'm picky.
2) Create two images for each button, essentially identical but with a different background. This seems like unnecessary work, and since this problem is coming up repeatedly, I want a solution for the future as well.
I hope somebody's figured out a decent solution to this by now. Thanks in advance.
Since UIButton has two image layers, an image and a background image, I think you could accomplish what you want by using just two background images for all your buttons. One image shows a border and the other does not. Swap the backgrounds out when the control state changed.
//
// TabBarSingleton.h
#import <Foundation/Foundation.h>
#interface TabBarSingleton : UITabBarController <UITabBarControllerDelegate>{
NSRecursiveLock *barLock;
UIButton *Button;
UIButton *favoriteButton;
}
#property(nonatomic, retain) UIButton *Button;
#property(nonatomic, retain) UIButton *favoriteButton;
- (void) ButtonPressed;
- (void) favoriteButtonPressed;
#end
///////////////////////////////////
If you want the the borders only, then you have only one choice of using two images for the two states otherwise if your purpose is to differentiate between two states then you can do it by changing alpha a little bit of the selected button this will give the effect like toggle buttons, you can also disable the selected button and enable it again when the other button is pressed.
Hope this will give you a fair idea.
//
// TabBarSingleton.m
// Created by ArunDhwaj on 9/7/10.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import "TabBarSingleton.h"
#implementation TabBarSingleton
#synthesize Button, favoriteButton;
- (id) init
{
if (self = [super initWithNibName: nil bundle: nil])
{
barLock = [[NSRecursiveLock alloc] init];
}
self.delegate = self;
return self;
}
+ (TabBarSingleton *) defaultBar
{
}
- (void)viewDidLoad
{
NSLog(#"TabBarSingleton: viewDidLoad");
//Hiding TabBar
self.tabBar.hidden = YES;
//Creating a UIView, its frame is same as tabBar frme
CGRect tabbarFrame = self.tabBar.frame;
UIView* customTabbarView = [[UIView alloc] initWithFrame:tabbarFrame];
UIImageView *newsFeedImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"newsfeeds_normal.png"]];
newsFeedImg.frame = CGRectOffset(newsFeedImg.frame, 0, 1);
Button = [UIButton buttonWithType:UIButtonTypeCustom];
[Button setFrame:newsFeedImg.frame];
[Button setBackgroundImage:newsFeedImg.image forState:UIControlStateNormal];
[Button setBackgroundImage:[UIImage imageNamed:#"newsfeeds_active.png"] forState:UIControlStateHighlighted];
[Button addTarget:self action:#selector(newsFeedsButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[customTabbarView addSubview:Button];
//[newsFeedImg release];
CGRect newsFeedFrame = newsFeedImg.frame;
UIImageView *favoriteImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"favorites_normal.png"]];
favoriteImg.frame = CGRectMake(newsFeedFrame.size.width, newsFeedFrame.origin.y, newsFeedFrame.size.width, newsFeedFrame.size.height);
favoriteButton = [UIButton buttonWithType:UIButtonTypeCustom];
[favoriteButton setFrame:favoriteImg.frame];
[favoriteButton setBackgroundImage:favoriteImg.image forState:UIControlStateNormal];
[favoriteButton setBackgroundImage:[UIImage imageNamed:#"favorites_active.png"] forState:UIControlStateHighlighted];
[favoriteButton addTarget:self action:#selector(favoriteButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[customTabbarView addSubview: favoriteButton];
//[favoriteImg release];
[self.view addSubview:customTabbarView ];
[self newsFeedsButtonPressed];
}
- (void) newsFeedsButtonPressed
{
NSLog(#"TabBarSingleton: newsFeedsButtonPressed");
self.selectedIndex = 0;
//Keeping Highlighted newsFeed tab
UIImageView *newsFeedImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"newsfeeds_active.png"]];
[Button setImage: newsFeedImg.image forState:UIControlStateNormal];
//Keeping normal others tab icons
UIImageView *favoriteImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"favorites_normal.png"]];
[favoriteButton setImage: favoriteImg.image forState:UIControlStateNormal];
}
- (void) favoriteButtonPressed
{
NSLog(#"TabBarSingleton: favoriteButtonPressed");
self.selectedIndex = 1;
//Keeping Highlighted newsFeed tab
UIImageView *newsFeedImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"newsfeeds_normal.png"]];
[Button setImage: newsFeedImg.image forState:UIControlStateNormal];
//Keeping normal others tab icons
UIImageView *favoriteImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"favorites_active.png"]];
[favoriteButton setImage: favoriteImg.image forState:UIControlStateNormal];
#pragma mark UITabBarControllerDelegate
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
NSLog(#"TabBarSingleton: shouldSelectViewController");
return YES;
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
NSLog(#"TabBarSingleton: didSelectViewController");
}
- (void) dealloc
{
//[barLock release];
[super dealloc];
}
#end