Placeholder for UITextView - uitextview

Anyone ever implements something in UITextView that stopping it from receiving future inputs when the text length is smaller than certain threshold? I plan to implement a textview like we have in the mail composer interface. We have a placeholder "Subject" there, and the cursor starts after.
Placeholder in UITextView
Inspired from this question, I wonder if there are some methods which could be used to stop changing the text in the UITextView once the cursor is moving back to the placeholder string.
Any ideas?

What about just clearing it, then pre-pending that text to whatever the user submits?

Well you could use something like..
- (void)textViewDidBeginEditing:(UITextView *)textView
{
if (self.textView.textColor != [UIColor blackColor]) {
self.textView.text = #"";
self.textView.textColor = [UIColor blackColor];
}
}
- (void)textViewDidEndEditing:(UITextView *)textView
{
//To display the placeholder text
if (![self.textView.text length]) {
self.textView.text = #"Description";
self.textView.textColor = [UIColor lightGrayColor];
}
}

Related

WKWebView not rendering correctly in iOS 10

I have WKWebView inside the UITableViewCell. The web view load request and then after finished loading, I'll resize the web view height to be equal to its content height, then adjust table view cell height to fit accordingly.
What happened was the web view only displays the area that fit the screen size. When I scroll down, everything is white. But I see that the web view rendered with correct height, tap and hold on the white area on the web view still see selection. Zooming with pinch makes the web view area that displaying on the screen visible, but other areas sometimes become white.
It works fine on iOS 8 and 9. I have created a sample project to demonstrate this behaviour here:
https://github.com/pawin/strange-wkwebview
Open Radar:
https://openradar.appspot.com/radar?id=4944718286815232
Update: This issue is resolved in iOS11
You need to force the WKWebView to layout while your UITableView scrolls.
// in the UITableViewDelegate
func scrollViewDidScroll(scrollView: UIScrollView) {
if let tableView = scrollView as? UITableView {
for cell in tableView.visibleCells {
guard let cell = cell as? MyCustomCellClass else { continue }
cell.webView?.setNeedsLayout()
}
}
}
func reloadWKWebViewIfNeeded() {
for cell in self.tableView.visibleCells {
guard let webviewCell = cell as? WebviewCell else { continue }
// guard cell height > screen height
webviewCell.webview.reload()
}
}
override func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
guard !decelerate else { return }
self.reloadWKWebViewIfNeeded()
}
override func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
self.reloadWKWebViewIfNeeded()
}
Not the best solution though, but at least user can see the rest of the content
I have the same problem - add a WKWebView to a UITableViewCell, and I solved this problem by these steps:
1.Create a UITextView instance and add it to UITableView's superview(UIViewControllew.view)
2.implement codes in scrollViewDidScroll like this:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[self.xxtextView becomeFirstResponder];
[self.xxtextView resignFirstResponder];
}
These codes may cause increased cpu performance overhead, you can fix it by some way such us use a temp variable as threshold value.
I don't think this is a perfect solve method, but it works for me.
Eventually I realized that textview becomeFirstResponder just led the webview layout again, so you can just fix it like this:
CGFloat tempOffset = 0;
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (!tempOffset || ABS(scrollView.contentOffset.y - tempOffset) > ScreenHeight/2)
{
[self.wkWebView setNeedsLayout];
tempOffset = scrollView.contentOffset.y;
}
}
In objective-C this is how I solve the problem.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
NSArray * visibleCell = [self.tableView visibleCells];
for (CustomUITableViewCell * cell in visibleCell) {
if ([cell isKindOfClass:[CustomUITableViewCell class]]) {
[cell.wkWebView setNeedsLayout];
}
}
}
That code will collect all visible cell and do the setNeedsLayout in fast enumeration during user scroll.
Im also have uitableview with cell with wkWebView. And i stack with same problem. But timely you can fix this with this code. By performance do not worry. I tested this solution on iphone 5s and it was taken 10-15% CPU only when you scrolling uitableView with visible web cell.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
//TODO: Remove this fix when WKWebView will fixed
if let cell = tableView.cellForRow(at: IndexPath(row: 1, section: 0)) as? WKWebViewCell {
// Here we take our cell
cell.wkWebView?.setNeedsLayout()
// here is "magic" (where wkWebView it is WKWebView, which was
// previously added on cell)
}
}

Cancel button in searchBar ios 8

tell me how to change the text on the Cancel button in searchBar?
Image: http://i.stack.imgur.com/8G1ZM.png
you can do that in this delegate method of UISearchBar
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
[theSearchBar setShowsCancelButton:YES animated:NO];
for (UIView *subView in theSearchBar.subviews){
if([subView isKindOfClass:[UIButton class]]){
[(UIButton*)subViewsetTitle:#"Button Title"forState:UIControlStateNormal];
}
}
}
UPDATE
after a long way searching the only way i got working in swift
is to set a custom UIBarButtonItem but you will need to show the search bar on the navigation
in ViewDidLoad()
self.searchDisplayController?.displaysSearchBarInNavigationBar = true
and in Delegate Method
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
var barButton = UIBarButtonItem(title: "Button Title", style: UIBarButtonItemStyle.Done, target: self, action: "here")
self.searchDisplayController?.navigationItem.rightBarButtonItem = barButton
}
i hope that works with you
«Another UPDATE
as you said in comments you will need to localize your application, in your case you will only need to localize the storyBoard
first navigate to your project settings then info, under localizations click the + button and add your own languages then check only StoryBoard
and now you have localized your app but you might don't see the changes until you remove the app and install it again or if the device language is set to english you will need to write 2 lines of code to change the language manually here is it
var str:NSString = "ar" // ar stands for arabic you put here you own language small character
var myArray:NSArray = [str]
NSUserDefaults.standardUserDefaults().setObject(myArray, forKey: "AppleLanguages")
and your button will looks like this
if you want to know more about localization see this Internationalization Tutorial for iOS [2014 Edition]
if you still need help till me :)
There are 2 solutions.
set key/value
[self.searchController.searchBar setValue:#"취소" forKey:#"_cancelButtonText"];
This solution works well, but you have to know that _cancelButtonText property is not public property.(You can not find this property in the documentation page.)
And It's not sure that this solution can pass the apple review process. So, use solution 2 please.
use a delegate.
You can change cancel button title(iOS8) within willPresentSearchController method.
(Assume that the searchBar is in tableView headerView)
- (void)willPresentSearchController:(UISearchController *)searchController{
// You have to set YES showsCancelButton.
// If not, you can not change your button title when this method called
// first time.
self.searchController.searchBar.showsCancelButton = YES;
UIView* view=self.searchController.searchBar.subviews[0];
for (UIView *subView in view.subviews) {
if ([subView isKindOfClass:[UIButton class]]) {
// solution 1
UIButton *cancelButton = (UIButton*)subView;
[cancelButton setTitle:NSLocalizedString(#"취소", nil) forState:UIControlStateNormal];
}
}
}
Also, You can get infomation about the searchBar through a view debugging tools in Xcode. Set a breakPoint at the willPresentSearchController method.
Good luck.
Actually, the cancel button is not a top view in the Search bar. You should search for it recursively.
-(UIButton*)findButtonInView:(UIView*)v{
for (UIView *subView in v.subviews){
if([subView isKindOfClass:[UIButton class]]){
return (UIButton*)subView;
}else if([subView isKindOfClass:[UIView class]]){
UIButton* btn = [self findButtonInView:subView];
if(btn){
return btn;
}
}
}
return nil;
}
//...
UIButton* searchButton = [self findButtonInView:self.searchBar];

UITextView to Mimic UITextField [for basic round corner text field]

I want to have UITextField with multiple lines, after a quick google on this issue I found that I should use TextView so I did switch my code to use UITextView when I want multiple lines. My View still have other one line textField that I want to keep.
To make my TextView looks like TextField, I had to add code to set border and radius, but they look a little bit different on iOS7. Does anyone know:
what is the color for the UITextField border? when both enabled and disabled so I can sent my textview to match it.
what is radius of the corner of TextField.
what is the background color for UITextField when it is disabled[attached picture shows the text field has lighter shade of grey when it is disabled]? so i can set my text view to the same color when i disable user interaction.
If there is away to keep using textfield for multiline text, I am all ears and i switch to use it.
Best Regards,
I use this:
textView.layer.borderColor = [[UIColor colorWithRed:215.0 / 255.0 green:215.0 / 255.0 blue:215.0 / 255.0 alpha:1] CGColor];
textView.layer.borderWidth = 0.6f;
textView.layer.cornerRadius = 6.0f;
little differences in the params make it looks more like UITextField(I hope).
I use this:
#import <QuartzCore/QuartzCore.h>
-(void) textViewLikeTextField:(UITextView*)textView
{
[textView.layer setBorderColor:[[UIColor colorWithRed:212.0/255.0
green:212.0/255.0
blue:212.0/255.0
alpha:1] CGColor]];
[textView.layer setBorderWidth:1.0f];
[textView.layer setCornerRadius:7.0f];
[textView.layer setMasksToBounds:YES];
}
and get a good resut.
I have a small subclass of UITextView that gives in iOS 7 the same look as the UITextField
The interface is empty:
#interface MyTextView : UITextView
#end
The implementation overwrites the initialization and the setter of the 'editable' property:
#implementation MyTextView
//================================================================================
- (id) initWithFrame: (CGRect) frame
{
self = [super initWithFrame:frame];
if (self)
{
[self commonInit];
}
return self;
}
//================================================================================
- (id) initWithCoder: (NSCoder *) aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self commonInit];
}
return self;
}
//================================================================================
- (void) commonInit
{
self.layer.borderWidth = 1.0f;
self.layer.borderColor = [[UIColor colorWithRed:232.0/255.0
green:232.0/255.0 blue:232.0/255.0 alpha:1] CGColor];
self.layer.cornerRadius = 6;
}
//================================================================================
- (void) setEditable: (BOOL) editable
{
[super setEditable:editable];
if (editable)
{
self.backgroundColor = [UIColor whiteColor];
}
else
{
self.backgroundColor = [UIColor colorWithRed:250.0/255.0
green:250.0/255.0 blue:250.0/255.0 alpha:1];
}
}
//================================================================================
#end
This is the closest I got with enabled UITextView
[yourTextView.layer setBorderColor:[[[UIColor lightGrayColor] colorWithAlphaComponent:0.2] CGColor]];
[yourTextView.layer setBorderWidth:2.0];
yourTextView.layer.cornerRadius = 5;
yourTextView.clipsToBounds = YES;
yourTextView.textColor = [UIColor lightGrayColor];

displaying Wiki mobile page in UIWebView within UIPopoverController

I try to open wiki mobile version webpage by a UIWebView within a UIPopoverController. the problem is, not matter how I set my contentSizeForViewInPopover, or just UIWebView frame, or simply set UIWebView.scalesPageToFit = YES. the Wiki mobile version page content size seem to larger than my UIWebView. But if I use it on iPhone, there's no such problem. here's my code for popover controller:
//create a UIWebView UIViewController first
WikiViewController *addView = [[WikiViewController alloc] init];
addView.contentSizeForViewInPopover = CGSizeMake(320.0, 480.0f);
//then create my UIPopoverController
popover = [[UIPopoverController alloc] initWithContentViewController:addView];
popover.delegate = self;
[addView release];
//then get the popover rect
CGPoint pointforPop = [self.mapView convertCoordinate:selectAnnotationCord
toPointToView:self.mapView];
CGRect askRect = CGRectMake((int)pointforPop.x, (int)pointforPop.y+10, 1.0, 1.0);
[popover presentPopoverFromRect:askRect
inView:self.mapView
permittedArrowDirections:UIPopoverArrowDirectionRight animated:YES];
[self.mapView deselectAnnotation:annotation animated:YES];
and this is my code on creating UIWebView:
- (void)viewDidLoad
{
wikiWebView = [[UIWebView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 480.0f)];
wikiWebView.scalesPageToFit = YES;
//or No, doesn't matter, it all get larger than this
wikiWebView.delegate = self;
self.view = wikiWebView;
}
all code seem to be typical...
I wonder if anyone can shed me some light, thank you so much.
This is an enhanced version of auco answer, where if the viewport meta tag is not present it will be added:
- (void)webViewDidFinishLoad:(UIWebView*)webView
{
int webviewWidth = (NSUInteger)webView.frame.size.width;
if (!webView.loading) {
NSString *jsCmd = [NSString stringWithFormat:#"try {var viewport = document.querySelector('meta[name=viewport]');if (viewport != null) {viewport.setAttribute('content','width=%ipx, initial-scale=1.0, user-scalable=1');} else {var viewPortTag=document.createElement('meta');viewPortTag.id='viewport';viewPortTag.name = 'viewport';viewPortTag.content = 'width=%ipx, initial-scale=1.0, user-scalable=1';document.getElementsByTagName('head')[0].appendChild(viewPortTag);}} catch (e) {/*alert(e);*/}", webviewWidth, webviewWidth];
[webView stringByEvaluatingJavaScriptFromString:jsCmd];
}
}
Here is the Javascript pretty formatted code we are injecting in the WebView with a width of 320px
try {
var viewport = document.querySelector('meta[name=viewport]');
if (viewport != null) {
viewport.setAttribute('content',
'width=320px, initial-scale=1.0, user-scalable=1');
} else {
var viewPortTag = document.createElement('meta');
viewPortTag.id = 'viewport';
viewPortTag.name = 'viewport';
viewPortTag.content = 'width=320px,initial-scale=1.0, user-scalable=1';
document.getElementsByTagName('head')[0].appendChild(viewPortTag);
}
} catch (e) {
/*alert(e);*/
}
you can remove the try/catch if you want.
oh, i found in another QA that sometimes if html got a line "width=device-width", and you load a webview from popover controller, this popover controller will automatically send out device-width, not the view width you specified, and make your view ugly and funky. in that post it is a jQuery issue, and it solved with a jQuery way. In my problem, it is just a html issue in wiki mobile version. so I try another way, but similar.
I simple add a code in webViewdidload delegate method, first get URL html into a NSString, then use NSString instance method to search for "device-width" in loaded html, and replace it with my view width to make it a new NSString, then load this page with this new NSString. that's it.
- (void) webViewDidFinishLoad:(UIWebView *)webView
{
if (!alreadyReload)
{
NSString *webHTML = [NSString stringWithContentsOfURL:webView.request.URL encoding:NSUTF8StringEncoding error:NULL];
NSRange range = [webHTML rangeOfString:#"device-width"];
if ((range.location!=NSNotFound)&&(range.length != 0))
{
webHTML = [webHTML stringByReplacingOccurrencesOfString:#"device-width" withString:#"whatever width you need" options:0 range:range];
[webView loadHTMLString:webHTML baseURL:wikiWebView.request.URL];
alreadyReload = YES;
}
}
}
something like this.
by the way, since I only use this on wiki mobile version, the html is simple and this kind of compare and replace is pretty easy. if you wanna use it in a more general case, you might use other way.
It would be much more efficient to manipulate the device-width via JavaScript rather than altering the html after it has fully loaded and then reloading the full page with modified html again.
This should work (and also consider if it's even necessary to change the viewport width):
- (void)webViewDidFinishLoad:(UIWebView *)aWebView {
if(aWebView.frame.size.width < aWebView.window.frame.size.width) {
// width=device-width results in a wrong viewport dimension for webpages displayed in a popover
NSString *jsCmd = #"var viewport = document.querySelector('meta[name=viewport]');";
jsCmd = [jsCmd stringByAppendingFormat:#"viewport.setAttribute('content', 'width=%i, initial-scale=1.0, user-scalable=1');", (NSUInteger)aWebView.frame.size.width];
[aWebView stringByEvaluatingJavaScriptFromString:jsCmd];
}
// stop network indicator
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}

How to keep a drag able object inside the frame of a view

I have a button that can be dragged around on the screen. I was wondering if there is a way to keep the button inside the frame of the view.
I have used this code to make the button drag able:
UIPanGestureRecognizer *buttonPanRecognizer;
buttonPanRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(setObjectLocation:)];
[NewButton addGestureRecognizer:buttonPanRecognizer];
- (void)setObjectLocation:(UIPanGestureRecognizer *)recognizer {
CGPoint location = [recognizer locationInView:self.view];
if (CGRectContainsPoint([NewButton frame], location)) { // NewButton
NewButton.center = location;
}
else if (CGRectContainsPoint([NewLabel frame], location)) { // NewLabel
NewLabel.center = location;
} }
I also want to be able to keep other kinds of objects inside.
Thansk in advance :)
The problem is that it is possible to drag parts of the UIButton outside the screen.
I have to agree that your problem is not quite clear. What is all the stuff with the label supposed to to. Generally, to keep a button inside a frame, you have everything you need already there:
UIPanGestureRecognizer* buttonPanRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(setObjectLocation:)];
[NewButton addGestureRecognizer:buttonPanRecognizer];
- (void)setObjectLocation:(UIPanGestureRecognizer *)recognizer {
CGPoint location = [recognizer translationInView:self.view];
if (CGRectContainsPoint(self.view.frame, location)) {
NewButton.center = location;
}
}
What's the problem? Just keep the button's origin within a rect (frame.x,frame.y,frame.width - button.width,frame.height - button.height).

Resources