user5831081
user5831081

Reputation:

How to make a view scroll? Just like Instagram's profile

UIView,SegmentedController & UIContainerView in a ScrollView or something similar?

In my storyboard I have a VC containing a UIView at the top, segmented controller in the middle & 2 ContainerViewControllers at the bottom with embeded segue's to new VC's.

In the new VC's I have a TableView & a CollectionView (For example, the Instagram profile).

My issue is that I need the SegmentedController and UIView to scroll with the ContainerView(TableView/CollectionView), at the moment only the ContainerView part scrolls and the parts above that are fixed.

Now I'm guessing I probably need to put everything into a UIScrollView, so I tried that & placed all the costraints correctly. But when It came to configuring it in the Swift file, I only really now how to set the height of the scroll but oviously the height I need can vary and isn't a fixed height!

If anyone can help me here that would be fantastic, or maybe point me towards a similar question already asked here? I have already looked, but did not find anything unfortunately!

Here's an image below explaining basically what I'm after, if above I wasn't very clear..

here is an example you can see: https://github.com/Jackksun/ScrollIssue

enter image description here

Upvotes: 13

Views: 3198

Answers (3)

user5590595
user5590595

Reputation:

So as I understood, you want to make your scroll view receive touches outside its bounds. You can achieve this by overriding hitTest:withEvent: method on the view that is actually receiving touches.

Here is an example of what I did in my project. I subclassed UIView and redirected all touches it was receiving to the specific view. In your case, you will redirect all the touches to scroll view.

.h file:

@import UIKit.UIView;

/*!
 @class         TouchableView
 @abstract      Touchable view.
 */
@interface TouchableView : UIView

/*!
 @property      viewToReceiveTouches
 @abstract      View that receives touches instead of a given view.
 */
@property (nonatomic, weak) IBOutlet UIView *viewToReceiveTouches;

@end
.m file:

@import UIKit.UIButton;
@import UIKit.UITableView;
@import UIKit.UITextField;

#import "TouchableView.h"

@implementation TouchableView

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if ( [self shouldViewReceiveTouch:self inPoint:point] )
    {
        return [super hitTest:point withEvent:event];
    }
    else if ( CGRectContainsPoint(self.bounds, point) && self.isUserInteractionEnabled )
    {
        return self.viewToReceiveTouches;
    }

    return nil;
}

- (BOOL)shouldViewReceiveTouch:(UIView *)view inPoint:(CGPoint)point
{
    if ( !CGRectContainsPoint(view.bounds, point) || !view.isUserInteractionEnabled )
    {
        return NO;
    }

    if ( [view isKindOfClass:[UIButton class]] ||
         [view isKindOfClass:[UITextField class]] ||
         [view isKindOfClass:[UITableViewCell class]] ||
         [view isKindOfClass:[UITableView class]] )

    {
        return YES;
    }

    for ( UIView *subview in view.subviews )
    {
        if ( [self shouldViewReceiveTouch:subview inPoint:[view convertPoint:point toView:subview]] )
        {
            return YES;
        }
    }

    return NO;
}

@end

Upvotes: 2

thibaut noah
thibaut noah

Reputation: 1514

Since your height can vary, the easiest way in my opinion to do what you want is to put everything in a UICollectionView. Segue? No problem, implement didSelectRowAtIndexPath, change your datas and height and reload the UICollectionView. You can also add the UICollectionView to a simple UIView, that will allow you to put some static content on top of it.

Here is a sample app to demonstrate this : https://github.com/tirrorex/Apps/tree/master/Swift/Sampleapp

You will have to implement a dynamic height, you can find some threads on this (basically you can make a special case for the cell containing your collectionview/tableview so that this cell will be load from nib, that might help you): UICollectionView Self Sizing Cells with Auto Layout

Upvotes: 1

truongky
truongky

Reputation: 1147

You can set dynamic size for the scrollview content. Here what I did.

  • Define dynamicHeight to store your new TableView/CollectionView height.
  • Everytime you change the segment control, get the child controller height and update the scrollview content size.

Take a look at my code (demo here)

@IBAction func selectPage(sender: AnyObject) {

    // clear all child controller before load new controller 
    for controller in childViewControllers {

        controller.removeFromParentViewController()
    }

    for view in pageContainer.subviews {

        view.removeFromSuperview()
    }

    let segment = sender as! UISegmentedControl

    if segment.selectedSegmentIndex == 0 {

        createImageController()
    }
    else {

        createTextController()
    }

    updateScrollContentSize()
}

func updateScrollContentSize() {

    // 150 is your view and segment height
    scrollView.contentSize = CGSize(width: view.frame.size.width, height: dynamicHeight + 150)
}

func createTextController() {

    let textController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("TextController") as! TextController
    dynamicHeight = textController.getTableContentHeight()
    textController.tableView.scrollEnabled = false

    self.addChildViewController(textController)
    pageContainer.addSubview(textController.view)
    textController.view.frame = CGRectMake(0, 0, pageContainer.frame.size.width, dynamicHeight)
}

func createImageController() {

    let imageController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("ImageShowController") as! ImageShowController
    dynamicHeight = imageController.getTableContentHeight()
    imageController.tableView.scrollEnabled = false

    self.addChildViewController(imageController)
    pageContainer.addSubview(imageController.view)
    imageController.view.frame = CGRectMake(0, 0, pageContainer.frame.size.width, dynamicHeight * 2)
}

Hope this can help.

Upvotes: 1

Related Questions