Add buttons and texts in UITextView - iphone

Hi friends i want to create a view in that I can add texts and buttons to. And I want to maintain the sequence. Like in a text view i want to add texts then buttons then again texts.
And also want to edit in same area.
I can add buttons in UITextview but how do I maintain the sequence of text that i added after button and before any button ?
Is there any sample code for it ?
I am adding buttons in UITextView by
UIButton *myButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
myButton .frame = CGRectMake(100, myTextView.contentSize.height, 90, 30);
[myButton setTitle:#"button text" forState:UIControlStateNormal];
[myTextView addSubview:myButton ];
but i can not able to move cursor after this button.

Can you not add UILabel and UITextField controls in the same manner, using contentSize.height each time?

Create a uiview subclass for the parent of the text view and override hit test sort of like this:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
// Check if the touch occurs within a rect or below a certain point
BOOL isInsidePassThroughArea = point.y + self.textView.contentOffset.y < 72.f;
if (isInsidePassThroughArea) {
return [self.contentView hitTest:point withEvent:event];
}
return [super hitTest:point withEvent:event];
}

Related

UIButton receiving touch events outside bounds when set as leftView of UITextField

This has been a bit of a head scratcher for me. In an app I'm building I am using a UITextField, and adding a button as the leftView property. However, it seems that on an iPad (both sim and on device), the button is receiving touches that are well outside its bounds. This is interfering with the ability of the UITextField to become the first responder when the user touches the placeholder text. It seems that when touching the placeholder text, the events are being handled by the button instead of the text field itself. Strangely, this only appears to happen on iPad; it works as expected on the iPhone.
Here is some simple code demonstrating the problem:
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10.0f,
10.0f,
(self.view.frame.size.width - 20.0f),
35.0f)];
textField.borderStyle = UITextBorderStyleRoundedRect;
textField.placeholder = #"Test text";
[self.view addSubview:textField];
UIButton *addButton = [UIButton buttonWithType:UIButtonTypeContactAdd];
[addButton addTarget:self action:#selector(touchDown:) forControlEvents:UIControlEventTouchDown];
[addButton addTarget:self action:#selector(touchUpInside) forControlEvents:UIControlEventTouchUpInside];
[addButton addTarget:self action:#selector(touchUpOutside) forControlEvents:UIControlEventTouchUpOutside];
textField.leftView = addButton;
textField.leftViewMode = UITextFieldViewModeAlways;
}
- (void)touchDown:(id)sender {
NSLog(#"touchDown");
}
- (void)touchUpInside {
NSLog(#"touchUpInside");
}
- (void)touchUpOutside {
NSLog(#"touchUpOutside");
}
It seems that sometimes touches are still perceived as being inside even though they appear to be outside the button's bounds. Then getting even further right, the button only receives UIControlEventTouchDown then UIControlEventTouchUpOutside.
2013-07-25 11:51:44.217 TestApp[22722:c07] touchDown
2013-07-25 11:51:44.306 TestApp[22722:c07] touchUpInside
2013-07-25 11:51:44.689 TestApp[22722:c07] touchDown
2013-07-25 11:51:44.801 TestApp[22722:c07] touchUpOutside
EDIT
Here is an example with the background color of the button changed as well as the approximate zones that trigger the events above. Also, I checked the frame of the button and it is less than 30px wide.
I sat down and spent some more time on this last night. I was already subclassing UITextField in my real application, so I ended up overriding -(id)hitTest:withEvent: as seen below. This has been working fine so far.
- (id)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if ([[super hitTest:point withEvent:event] isEqual:self.leftView]) {
if (CGRectContainsPoint(self.leftView.frame, point)) {
return self.leftView;
} else {
return self;
}
}
return [super hitTest:point withEvent:event];
}
I verified your results. I think it's most likely a bug in UITextView. Unfortunately, for some reason if you set leftView, events in that area are being sent to the wrong view (on the iPad).
I don't have a simple workaround for you since adjusting the frame of the leftView has no effect. I think it needs to be fixed at a lower level than we have access to. Maybe report the bug to Apple and live with it for now?
You could track the location of the touch and ignore it if it's out of bounds, but it seems like a lot of work for a minor bug?
Just met this question too, for some other solution I found is adding a check whether the event point located inside the button.
- (void)touchUpInside:(UIButton *)sender event:(UIEvent *)event
{
CGPoint location = [[[event allTouches] anyObject] locationInView:sender];
if (!CGRectContainsPoint(sender.bounds, location)) {
// Outside of bounds, so ignore:
return;
}
// Inside our bounds, so continue as normal:
}

Set UIImageView background color upon user intervention

I am developing an application in which I have a horizontal scroller.
The scroller area comprise of different colors [which are nothing but UIImageView of colors].
Above the scroller area is a canvas [which is also a UIImageView].
Now, what I want is that when I select any color in the scroller area, it should set on the canvas.
It is pretty much like a color picker but I am already providing solid color options to be selected by the user.
How should I go about it ? Any sample Code to get me started or my mind kicking would be awesome ?
Thanx a ton
To implement it easily.
Use UIView not UIImageView
Set UIView backgroundColor and place it on the scroll
Set UITapGestureRecognizer on views,Refer here
when a purticular view is touched you have its instance of view which
is touched
get the background color of the view and set it in the scroller
Can you take UIButtons instead of UIImageViews inside your scrollView to show colours to be picked.
This will make the implementation easier. User will select any colour button and you will receive a callback in buttons action selector method. Then based on button tag or any property you can set the colour to your canvas.
In current implementation it will be tricky as you need to know the exact content offset where the tap is done to make out which UIImageView was pressed.
coding steps:
In your scroll view add UIButtons instead of UIImageView like:
UIButton* button = [[UIButton alloc] initWithFrame:someRect];
//put some tag to button
button.tag = someInt;
//add selector to each button to get callback
[view addTarget:self action:#selector(btnSelected:) forControlEvents:UIControlEventTouchUpInside];
[scrollView addSubview:button];
In the btnSelected method put this code:
-(IBAction)btnSelected:(id)sender;
{
UIButton* button = (UIButton*) sender;
if (button.tag == someInt) {
//do something like
canvas.backgroundColor = button.backgroundColor;
}
}
Instead of using UIImageViews or UIViews as suggested, I would put custom UIButtons for picking colors.
UIButton * colorButton;
//You will probably do these inside a for loop
colorButton = [UIButton buttonWithType:UIButtonTypeCustom];
[colorButton setFrame:CGRectMake(X, Y, buttonSize, buttonSize)];
[colorButton setTitle:#"" forState:UIControlStateNormal];
[colorButton setBackgroundColor:SOME_COLOR];
//Border visualization would be good if you are putting buttons side-by-side
[colorButton.layer setBorderWidth:1.0];
[colorButton.layer setBorderColor:[[UIColor darkGrayColor] CGColor]];
//You can use this tag to identify different buttons later
[colorButton setTag:INDEX+SOME_OFFSET]; //use loop index with some offset
[colorButton addTarget:self action:#selector(colorButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
-(void) colorButtonPressed:(UIButton *) sender
{
UIColor *selectedColor = sender.backgroundColor; //Or identify with sender.tag
[yourCanvas doSmtOnCanvas:selectedColor];
}
Initialize UIImageView then add gesture recognizer to all imageViews by calling this method.
- (void) setupImageView : (UIImageView *) imageView{
[imageView setUserInteractionEnabled:YES];
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(changeUIImageViewBackgroundColor:)];
tapGestureRecognizer.numberOfTapsRequired = 1;
[imageView addGestureRecognizer:tapGestureRecognizer];
}
Now change color of canvasView within the selector by following way:
- (void) changeUIImageViewBackgroundColor : (UITapGestureRecognizer *) recognizer{
UIImageView *imageView = (UIImageView *)[recognizer view];
[canvasView setBackgroundColor:[imageView backgroundColor]];
}
You can put a tap gesture in your scrollview and whenever a tap is made in the scroll check whether the tap is on the imageview. (You will get whether the tap point in on imageview or not) and according you can change the image.
Second alternative is to take a custom button and handle on its click.
Hope it helps

UIButton created in loop not clickable

Here's my problem:
I add several buttons to a scrollview in a loop:
for (int i = 0; i < [allEventArray count]; i++) {
UIButton *eventButton = [UIButton buttonWithType:UIButtonTypeCustom];
eventButton.tag = i + 10;
UIImage *normalImage = [UIImage imageNamed:#"rosterButton.png"];
normalImage = [normalImage
stretchableImageWithLeftCapWidth:normalImage.size.width/2
topCapHeight:normalImage.size.height/2];
[eventButton setBackgroundImage:normalImage
forState:UIControlStateNormal];
[eventButton addTarget:self action:#selector(gotoThisAirport)
forControlEvents:UIControlEventTouchUpInside];
[drawRosterView addSubview:eventButton];
}
I set the frame size and other stuff later on by opening the tag property.
All the buttons appear as advertised.
The problem is that only the first button in the view responds to clicking. The others just sit there chilling, doing nothing. How can this be? It driving me absolutely crazy!
Please help!
It sounds like your UIButton isn't fully inside your UIView.
Try only adding the UIButton to UIView and set a background color for the UIView to something like [UIColor greenColor]. You should then see if the UIButton is partially outside of the UIView.
Also, if you add an NSLog("click") call in -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; of the UIView, then you can click anywhere on screen and get feedback if the UIView detects the touch or not.

Touch and pull down a view

I have a uiview at the top of the interface (below the status bar) that only the bottom part of it is shown.
Actually, I want to make the red uiview to slide down to be entirely shown by drag such as the notificationcenter in the native iOS and not just by taping a button.
What should I use to "touch and pull down" the uiview so it could be shown entirely ?
No needs to find a workaround of drag-n-drop. An UIScrollView can do it without any performance loss brought by listening on touches.
#interface PulldownView : UIScrollView
#end
#implementation PulldownView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (!self) {
return self;
}
self.pagingEnabled = YES;
self.bounces = NO;
self.showsVerticalScrollIndicator = NO;
[self setBackgroundColor:[UIColor clearColor]];
double pixelsOutside = 20;// How many pixels left outside.
self.contentSize = CGSizeMake(320, frame.size.height * 2 - pixelsOutside);
// redArea is the draggable area in red.
UIView *redArea = [[UIView alloc] initWithFrame:frame];
redArea.backgroundColor = [UIColor redColor];
[self addSubview:redArea];
return self;
}
// What this method does is to make sure that the user can only drag the view from inside the area in red.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (point.y > height)
{
// Leaving useless touches to the views under it.
return nil;
}
return [super hitTest:point withEvent:event];
}
#end
How to use:
1. Initialize an instance of PulldownView.
2. Add any content you want to display to the instance using [addSubview:].
3. Hide the area in red.
[pulldownView setContentOffset:CGPointMake(0, heightOfTheView - pixelsOutside)];
This is a simple example. You can add any features to it like adding a titled button bar on the bottom of the draggable area to implement click-n-drop, or adding some method to the interface to reposition it by the caller.
Make a subclass of UIView.
Override touchesBegan:withEvent and touchesMoved:withEvent.
In the touchesBegan perhaps make a visual change so the user knows they are touching the view.
In the touchesMoved use
[[touches anyObject] locationInView:self]
and
[[touches anyObject] previousLocationInView:self]
to calculate the difference between the current touch position and the last touch position (detect drag down or drag back up).
Then if you're custom drawing, call [self setNeedsDisplay] to tell your view to redraw in it's drawRect:(CGRect)rect method.
Note: this assumes multiple touch is not used by this view.
Refer to my answer in iPhone App: implementation of Drag and drop images in UIView
You just need to use TouchesBegin and TouchesEnded methods. In that example, I have shown how to use CGPoint, Instead of that you have to try to use setFrame or drawRect for your view.
As soon as TouchesMoved method is called you have to use setFrame or drawRect (not sure but which ever works, mostly setFrame) also take the height from CGPoint.

How do I handle event when user touch up outside the UIView?

I have a custom popup menu in my iOS application. It is UIView with buttons on it. How do I handle event when user touch up outside this view? I want to hide menu at this moment.
You should create a custom UIButton that takes up the whole screen. Then add your subview on top of that button. Then when the user taps outside of the subview they will be tapping the button.
For example, make the button like this:
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:#selector(yourhidemethod:) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"" forState:UIControlStateNormal];
button.frame = self.view.frame;
[self.view addSubview:button];
(where yourhidemethod: is the name of the method that removes your subview.) Then add your subview on top of it.
Update: It looks like you're wanting to know how to detect where touches are in a view. Here's what you do:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self]; //location is relative to the current view
// do something with the touched point
}
Put it in full-screen transparent view and handle touches for it.
One idea is to have an invisible view(uicontrol) that is as big as the screen which then holds this custom popup.
It sounds like you'd be better served by deriving your menu from UIControl rather than UIView. That would simplify the touch handling, and all you'd have to do in this case would be to set a target and action for UIControlEventTouchUpOutside. The target could be the menu itself, and the action would hide or dismiss the menu.