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

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)];

Related

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.

UISwipeGestureRecognizer for subviews (UIVIew) not working

I have a View Controller with 3 subviews inside the self.view.
I'm trying to slide between them and it's not working.
Here is my code:
- (void)viewDidLoad
{
UISwipeGestureRecognizer *swipeGestureRecognizerLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(didSwipe:)];
swipeGestureRecognizerLeft.direction = UISwipeGestureRecognizerDirectionLeft;
for (UIView *subview in self.view.subviews)
{
if([subview isKindOfClass:[UIView class]] && !([subview isKindOfClass:[UIImageView class]]))
{
[subview addGestureRecognizer:swipeGestureRecognizerLeft];
NSLog(#"Load 2");
}
}
}
-(void) didSwipe:(UISwipeGestureRecognizer *) swipeRecognizer {
NSLog(#"Load swipe");
if (swipeRecognizer.direction==UISwipeGestureRecognizerDirectionLeft)
{
NSLog(#"swipe Left");
[self SlideToLeft];
}
}
I really see that "Load 2" is being printed 3 times but when I try to slide it's not working.
Thank you
Are you using a UIScrollView here? That could be the problem.
I think you can just use the standard UIScrollView delegate methods in this situation:
- (void) scrollViewDidScroll: (UIScrollView *) sender
{
NSLog(#"Scrolled!");
}
Otherwise these guys here, here and here had some trouble too, maybe the answers there could help you.
If you're not using a UIScrollView here? I should use one, why not? 3 Subviews and swiping to the next one sounds just like a nice UIScrollView example (use paging).
Good Luck!

UIScrollView scrollToTop not getting called for iPhone

I have a universal app, the code is the same. I have a UIScrollView in which has the scrollToTop working on the iPad but not on iPhone. I am pretty frustrated by this.
I know there's a similar thread posted here, but that is not the case. I used to have the scrolling to work before this both on the iPad and iPhone. Any idea what to look for?
The structure of the code is like this. I have a mainVC called A. I then have a VC called B. There is also another VC called C, which has a UIScrollView. I added C as B's child view controller. and then B as A's child VC. Now the scroll view on C did not have the scrollToTop working.
The delegate scrollViewShouldScrollToTop is also called only in the iPad, not in the iPhone.
Take a look at my answer to the question you've talked about. I've just added it a moment ago.
EDIT
I don't have the original code I've made, but it should be like that:
-(void)cleanUp:(UIScrollView*)view{
if([view isKindOfClass:[UIScrollView class]]){
view.scrollsToTop = NO;
}else{
for(UIScrollView* subview in view.subviews){
if([subview isKindOfClass:[UIView class]]){
[self cleanUp:subview];
}
}
}
}
and you can call it like this:
[self cleanUp:self.view];
You may also need even more tough variant of that routine (sometimes you may have a tableView inside a scrollView or something like that):
-(void)cleanUp:(UIScrollView*)view{
if([view isKindOfClass:[UIScrollView class]]){
view.scrollsToTop = NO;
}
for(UIScrollView* subview in view.subviews){
if([subview isKindOfClass:[UIView class]]){
[self cleanUp:subview];
}
}
}
I Just took the solution of #Ariel and done some improvements I want to share with you:
+ (void)globalDisableScrollToTop:(UIView *)_view;
{
// Check whether we got a scroll view
if ([_view isKindOfClass:[UIScrollView class]])
{
// Disable scroll to top
((UIScrollView *)_view).scrollsToTop = NO;
}
// Iterate all subviews
for (UIView *view in _view.subviews)
{
// Recursive call of this method
[self globalDisableScrollToTop:view];
}
}
Or without comments:
+ (void)globalDisableScrollToTop:(UIView *)_view;
{
if ([_view isKindOfClass:[UIScrollView class]])
((UIScrollView *)_view).scrollsToTop = NO;
for (UIView *view in _view.subviews)
[self globalDisableScrollToTop:view];
}
It now fixes all subviews and could be implemented as static method (of your root scroll view class).
If possible, Please paste the add subview code here. Looks like the problem is the view on which the scrollview is present is getting hide behind other view. Try changing the sequence of adding subview. Or you may also try bringSubviewtoFront property for setting the scrollview on top.
Let me know if it helps.

Rendering content after zoomed in for UIScrollView

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];
}

Find all controls of a type in a UIView

I am looking for a way to automatically localize texts on buttons/textfields etc and for this method I need to find all (for example) UIButton's on a UIView.
I tried the following 2 methods, but they both do no work like I want them to work:
for (UIView* subView in self.view.subviews)
{
NSLog(#"object class : %#", [subView class]);
if ([subView isMemberOfClass:[UIButton class]])
NSLog(#"Button found!");
}
The problem with this piece of code is that a RoundedRectButton does not match the UIButton class, while it really is just a UIButton.
I also tried the following:
for (UIButton* button in self.view.subviews)
{
// Do my stuff
}
But the stupid thing is, is that cocoa-touch actually just lists all subviews in that for-loop (also the UITextFields etc).
Is there a way to actually just get all UIButtons from a view? Or do I really need to find controls by looking at their selectors.
Why write one-off code like this when you can dial up the awesomeness by adding a category method to UIView using blocks? Take a look at the code at the very bottom. Using this recursive method with blocks you can do things like disable all UITextFields in a view controller's view:
[self.view forEachUITextFieldDoBlock:^(UITextField *textField) {
textfield.enabled = NO;
}];
Or fade out all UITextFields in a view controller's view:
[UIView animateWithDuration:0.25 animations:^{
[self.view forEachUITextFieldDoBlock:^(UITextField *textField) {
textField.alpha = 0.0;
}];
}
completion:^(BOOL finished){
// nothing to do for now
}];
Blocks are pretty amazing in that you can even pass other methods inside a block. For example, the code below passes each UITextField found to my inserAdornmentImage:forTextView method, which adds a custom background image to each text view:
[self.view forEachUITextFieldDoBlock:^(UITextField *textField) {
[self insertAdornmentImage:textFieldBGImage forTextField:textField];
}];
Blocks make the method incredibly flexible so you aren't having to write a specialized method each time you want to do something new with the controls you find. Here's the magic sauce:
#implementation UIView (Helper)
- (void) forEachUITextFieldDoBlock:(void (^)(UITextField *textField))block
{
for (UIView *subview in self.subviews)
{
if ([subview isKindOfClass:[UITextField class]])
{
block((UITextField *)subview);
} else {
[subview forEachUITextFieldDoBlock:block];
}
}
}
#end
the first method is correct, except you need to change isMemberOfClass function to isKindOfClass:
isKindOfClass: Returns a Boolean value
that indicates whether the receiver is
an instance of given class or an
instance of any class that inherits
from that class.