Rendering content after zoomed in for UIScrollView - iphone

I've looked around and it seems like people say you can re-render the data after you zoom in now that you know the scale factor for UIScrollView. I've also seen some posts about making your layer to a CATiledLayer and set the levelsOfDetailBias and levelsOfDetail.
What I have is a UIScrollView, and in it, a ResultsView which is a subclass of UIView:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
CATiledLayer *tiledLayer = (CATiledLayer *)self.layer;
tiledLayer.levelsOfDetailBias = 3;
tiledLayer.levelsOfDetail = 3;
self.opaque = YES;
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
+ (Class)layerClass {
return [CATiledLayer class];
}
In my class where I have the UIScrollView and ResultsView, I do:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.ResultsView;
}
Is this enough to have the text rerendered (sharp)? Or do I need to implement something in
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
}
If so, I'm not sure how to do that. In my class with UIScrollView and ResultsView, in ResultsView (in the XIB), I just have a couple of UILabels and UIViews (UIViews used for headings/footers for the view). So I do not know how to redraw those from ResultsView. Although ResultsView has the UILabels and UIViews as children of it in the XIB, I'm not sure how I would redraw those from the ResultsView class, and what I would need to do anyway.
Or is this the wrong approach? Do I just need to resize the UILabel and UIView by the scale factor in the scrollViewDidEndZooming: delegate method? TIA

I think you are taking the wrong approach. If your view consists of UILabels and UIViews that do not do any custom drawing, I would not mess with using a CATiledLayer backed view. Instead implement the scrollViewDidEndZooming:withView:atScale: delegate method and do something like this:
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
scale *= [[[self.scrollView window] screen] scale];
[view setContentScaleFactor:scale];
for (UIView *subview in view.subviews) {
[subview setContentScaleFactor:scale];
}
}

I have something small to add to the accepted solution that caused me a few minutes of pain just in case anyone else runs into the same thing.
Looping through all subviews in the view you're zooming and calling setContentScaleFactor doesn't take into account if any of the subviews themselves have subviews. If you have a more complicated setup like that, make sure to also loop through the subviews of those container views and call
[subview setContentScaleFactor:scale];
on each. I made a method that I can invoke to call setContentScaleFactor on all the subviews of a given view and call that for each "container view" on the screen.
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
scale *= [[[self.scrollView window] screen] scale];
[view setContentScaleFactor:scale];
for (UIView *subview in view.subviews)
{
[self setContentSizeForView:subview andScore:scale];
//Loop through all the subviews inside the subview
for(UIView *subSubview in subview.subviews)
{
[self setContentSizeForView:subSubview andScale:scale];
}
}
}
- (void) setContentSizeForView:(UIView*) view andScale:(float)scale
{
[view setContentScaleFactor:scale];
}

Related

UISearchBar placeholder aligning and cropping in iOS 7

In iOS 7 UISearchbar placeholder center-aligned and overlay the bookmarks button until search bar doesn't selected:
When it selected, it looks as expected:
I need it looks this way all the time. Thank you.
NEW SOLUTION:
//
// WPViewController.m
// test
//
// Created by VASANTH K on 02/01/14.
//
//
#import "WPViewController.h"
#interface WPViewController ()
{
UILabel *lableCopy;
}
#end
#implementation WPViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//[self fixSearchBar:searchBar];
// Do any additional setup after loading the view, typically from a nib.
self.searchBar.delegate=self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.searchBar resignFirstResponder];
//[self fixSearchBar:searchBar];
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self fixSearchBar:self.searchBar];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)searchBarTextDidBeginEditing:(UISearchBar *)search
{
[self fixSearchBar:self.searchBar];
}
-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
[self fixSearchBar:self.searchBar];
}
-(void)fixSearchBar:(UISearchBar*)searchBar
{
UITextField *searchField = [searchBar valueForKey:#"_searchField"];
// [searchField setValue:[UIColor blueColor] forKeyPath:#"_placeholderLabel.textColor"];
UILabel *lable=[searchField valueForKey:#"_placeholderLabel"];
if(!lableCopy)
{
lableCopy=[[UILabel alloc]initWithFrame:lable.frame];
lableCopy.font=lable.font;
[lableCopy setText:lable.text];
[lableCopy setTextColor:lable.textColor];
UIButton *button;
for (UIView *view in [[[[searchBar.subviews objectAtIndex:0] subviews] objectAtIndex:1] subviews]) {
if([view isKindOfClass:[UIButton class]])
{
button=(UIButton*)view;
break;
}
}
if(button)
{
//lable.hidden=YES;
CGRect newFrame=lable.frame;
newFrame.size.width=button.frame.origin.x-lable.frame.origin.x;
lableCopy.frame=newFrame;
[lableCopy adjustsFontSizeToFitWidth];
//lableCopy.backgroundColor=[UIColor blackColor];
[searchField addSubview:lableCopy];
lableCopy.text=lable.text;
//lableCopy.textColor=[UIColor redColor];
}
}
for (UIView *view in [[searchBar.subviews objectAtIndex:0] subviews]) {
if([view isKindOfClass:[UITextField class]])
{
// NSLog(#"%#",view);
NSLog(#"TextFieldPresent==>%#",view);
if([view isFirstResponder])
{
lable.hidden=NO;
lableCopy.hidden=YES;
}
else
{
lable.hidden=YES;
lableCopy.hidden=NO;
}
break;
}
}
}
#end
This solution is just adding new UILable view and hide the existing placeholder to give the real feel of searchBar.Again redisplay the actual placeholder when search Bar became active.
This may be a temporary hack to fix that UI issue in IOS7.
OLD SOLUTION:
[searchField setValue:[NSNumber numberWithBool:YES] forKeyPath:#"_placeholderLabel.adjustsFontSizeToFitWidth"];
will not work in ios7 because the size of lable used for disaplay the content is enough to show the text, the problem is the label width bug of ios7. it fails to re-size the label width.
there is little bit hack to fix this.
UITextField *searchField = [searchBar valueForKey:#"_searchField"];
UILabel *lable=[searchBar valueForKey:#"_placeholderLabel"];
lable.font=[UIFont fontWithName:lable.font.fontName size:10.0];
calculate the font-size based upon the search bar width of your own. I also tried to change the width of particular label but it never work.
-(void)viewDidAppear:(BOOL)animated{
self.searchBar.placeholder=#"woord hier invoeren";
}
-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
self.searchBar.placeholder=#"woord hier invoeren.......";
}
I'm not here to give you a general solution but if you have a placeHolder to add, the dumbest and easy way to do it is by truncating the placeHolder yourself, so instead of
searchBar.placeholder = #"woord hier invoeren";
let it be
searchBar.placeholder = #"woord hier invo...";
i tried to mess with the private methods of apple but with no luck:
the searchBar subviews are :
-UISearchBarBackground.
-UISearchBarTextField.
leave the UISearchBarBackground aside
the subviews of the UISearchBarTextField instance are :
-_UISearchBarSearchFieldBackgroundView.
-UIImageView.
-UISearchBarTextFieldLabel.
what i went for is trying to mess with the rect (i emphasis on the word mess as these are private methods) of the UISearchBarTextFieldLabel coz i'm pretty sure that its frame ain't rendered right when the searchBar button is shown (bookmark), if you choose searchBar.showsBookmarkButton = NO; the placeHolder text will be truncated as expected.
It's up to you, save yourself sometime and go with the dumb solution but that gets things done, or delve even further.
keep up the good work.

How can i set content offset on multiple scrollviews with one method?

I am having a little problem. I want to make all my scrollview scroll to the top when I press a UITableViewCell. Following is the code in didSelectRowAtIndexPath:
[self.tableView setContentOffset:CGPointZero];
[verbTableView setContentOffset:CGPointZero];
[seinhabenScrollView setContentOffset:CGPointZero];
[mdhPresensScroll setContentOffset:CGPointZero];
[mdhPreteritumScroll setContentOffset:CGPointZero];
[mhdScroll setContentOffset:CGPointZero];
....
There are more of those scrollview, and I want to put the all in one single object or something... I have tried following code:
for (UIScrollView *scrolls in topLayer.subviews)
{
[scrolls setContentOffset:CGPointZero];
}
Thanks!
The basic idea is right. It just depends upon how you identify the scroll views. You could do something like the following, which explicitly tests whether the subview is a kind of UIScrollView:
for (UIScrollView *scrollView in self.view.subviews)
{
if ([scrollView isKindOfClass:[UIScrollView class]])
scrollView.contentOffset = CGPointZero;
}
Or you can explicitly reference the specific scrollviews in question (in which case the class membership test isn't strictly needed):
for (UIScrollView *scrollView in #[seinhabenScrollView, mdhPresensScroll, mdhPreteritumScroll])
{
scrollView.contentOffset = CGPointZero;
}
Or, if you create an IBOutletCollection in IB, you can use that, too:
for (UIScrollView *scrollView in self.scrollViews)
{
[scrollView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
}
(Note, in that final example, I'm scrolling to the location in question with animation, providing the user some visual cue as to what just happened; that's completely up to you.)
In a comment above, you say that topView has subviews which, themselves, have subviews that are scrollviews, you'd have to do something like the following to handle this subview-of-subview situation:
for (UIView *subview in topLayer.subviews)
{
for (UIScrollView *scrollView in subview)
{
if ([scrollView isKindOfClass:[UIScrollView class]])
scrollView.contentOffset = CGPointZero;
}
}
Avoiding the dynamic type check, just place the views that can scroll into an array. Then, a little fancier, add an extension to scroll view so they can scroll to zero using no params, that let's us do the scrolling with an NSArray one-liner (makeObjectsPerform...)...
#interface UIScrollView (ScrollToZero)
- (void)scrollToZero; // a no-param method for scrolling to zero offset
#end
#implementation UIScrollView (ScrollToZero)
- (void)scrollToZero {
[self setContentOffset:CGPointZero animated:YES];
}
#end
NSArray *allMyScrolls = #[verbTableView, seinhabenScrollView, // and so on. put ONLY scrollViews in here
// you can make this array a property, initialized when the views are created
[allMyScrolls makeObjectsPerformSelector:#selector(scrollToZero)];

How to make custom button and cell shading for moving rows in UITable?

How can make custom button for moving rows in UITable?
I would like it to be transparent.
(Instead of this: )
Another thing is, when the cell is moved, it has shadow. Is it possible to remove it?
Try this...
You have to do this by subclassing UITableViewCell and overriding its setEditing:animated: method as follows:
The re-order control is a UITableViewCellReorderControl, but that's a private class, so you can't access it directly.
you could just look through the hierarchy of subviews and find its imageView.
- (void) setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing: editing animated: YES];
if (editing) {
for (UIView * view in self.subviews) {
if ([NSStringFromClass([view class]) rangeOfString: #"Reorder"].location != NSNotFound) {
for (UIView * subview in view.subviews) {
if ([subview isKindOfClass: [UIImageView class]]) {
((UIImageView *)subview).image = [UIImage imageNamed: #"yourimage.png"];
}
}
}
}
}
}
You can turn off the reordering control by setting -[UITableViewCell setShowsReorderControl:] to NO. After that you will need your own custom reordering implementation. I'm not sure what you can do about the shadow effect during a move.
If you really want to dig deep you can create your custom table view cell move UX.

How to detect zoom scale of UIWebView

I want to increase height of UIWebView while user zoom in (like default mail app in iPhone).
So, I have tried the code below to find scrollview in webview and add UIScrollViewDelegate to use scrollViewDidZoom for detecting zoom scale to increase height of webview on this method.
// MessageAppDelegate.h
#interface MessageAppDelegate : NSObject <UIApplicationDelegate,UIWebViewDelegate,UIScrollViewDelegate> {
UIWebView *webview;
UIScrollView *scrollview;
}
//MessageAppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
[self.window makeKeyAndVisible];
webview = [[UIWebView alloc] initWithFrame:CGRectMake(0, 150, 320, 100)];
webview.delegate = self;
webview.scalesPageToFit = YES;
webview.userInteractionEnabled = YES;
[webview loadHTMLString:#"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=6.0 user-scalable=yes\">test test" baseURL:nil];
[self.window addSubview:webview];
// Find scrollview in webview
for (UIView *view in webview.subviews) {
if ([view isKindOfClass:[UIScrollView class]]) {
// Get UIScrollView object
scrollview = (UIScrollView *) view;
scrollview.delegate = self;
}
}
return YES;
}
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale{
NSLog(#"scale %f",scale);
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView{
NSLog(#"scrollViewDidZoom %f",scrollview.zoomScale);
}
The problem is I cannot zoom in/out on the webview
but NSLog on scrollViewDisEndZooming method showed
scale 1.0
when I ended zooming
and scrollViewDidZoom method didn't show anything.
I want to detect zoom scale of webview for calculating its height on scrollViewDidZoom.
What I've done wrong?
Please help.
Thanks in advance.
I have done well for your code up,do following modificaitons:
you just get the scrollview class point ,then can get the scrollview.contentSize.width,which can change when you zoom in out,but scrollview.zoomScale always remains 1.so have to use contensize.width to calculate scale.
#interface dictViewController : UIViewController<UIWebViewDelegate,UITextFieldDelegate,UIGestureRecognizerDelegate,UIScrollViewDelegate>{
UIScrollView *scrollview;
......................
//scrollview.delegate = self;
for (UIView *view in webViewM.subviews) {
if ([view isKindOfClass:[UIScrollView class]]) {
// Get UIScrollView object
scrollview = (UIScrollView *) view;
//scrollview.delegate = self;
}
}
/*
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale{
//NSLog(#"scale zooming %f",scale);
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView{
//NSLog(#"scrollViewDidZoom %f",scrollview.zoomScale);
}*/
- (void)swipeRightAction:(id)ignored
{
NSLog(#"wid=%f", scrollview.contentSize.width);
NSLog(#"zoomscale=%f", scrollview.zoomScale);
}
I don't think there's a proper way to do it from the exposed APIs, but there is a hacky way.
A UIWebView contains a UIScrollView which can be given a delegate. Then when zooming changes, you (the delegate) get a callback called scrollViewDidZoom:.
In order to find the scroll view, you can get the subviews collection from the web view and iterate to see which one isKindOfClass:[UIScrollView class].
Now, UIWebView also conforms to UIScrollViewDelegate. So that may mean you are changing the web view's implementation, and that could be a Bad Idea. Test well.

UIScrollView Horizontal scrolling - Disable left scroll

How can I disable scrolling left on a UIScrollview. This is so users can only scroll right?
Thanks
*** UPDATE *****
This is what I have now. I have subclassed UIScrollView and overwritten the following methods
#implementation TouchScrollView
- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view {
NSLog(#"touchesShouldBegin: I was touched!");
return YES;
}
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
NSLog(#"touchesShouldCancelInContentView: I was touched!");
return NO;
}
In my viewController I have also set the following attributes:
scrollView.delaysContentTouches = NO;
scrollView.canCancelContentTouches = YES;
TouchesShouldBegin is being called but touchesShouldCancelInContentView is not being called and I cant figure out why!!
Thanks
just add this in your UIViewController UIScrollViewDelegate
float oldX; // here or better in .h interface
- (void)scrollViewDidScroll:(UIScrollView *)aScrollView
{
if (scrollView.contentOffset.x < oldX) {
[aScrollView setContentOffset: CGPointMake(oldX, aScrollView.contentOffset.y)];
} else {
oldX = aScrollView.contentOffset.x;
}
}
You should handle swipe gestures.
Check similar question here: iOS Advanced Gestures: Getting Swipe Direction Vector