12

I am creating app with UiScrollview and UIPagectontrol using Autolayout Programmatically, for

I have Created TKScroller as subclass of UIView, I am init it using Some Mode and Array.

TKScroller.m

-(void)setData{

[self layoutIfNeeded];
CGRect mainFrame=self.frame;


[self layoutIfNeeded];
CGRect mainFrame=self.frame;
UIView *lastview;
NSMutableArray* manualConstraints = [NSMutableArray array];

for (int i=0; i<arrayData.count ; i++)
{
    CGRect frame;
    frame.origin.x = scrollView.frame.size.width * i;
    frame.origin.y = 0;
    frame.size = scrollView.frame.size;

    UIView *subview = [UIView new];

    subview.backgroundColor = [self getRandomColor];
    [scrollView addSubview:subview];

    if (i==0)
    {

        NSLayoutConstraint* b1_top = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTop multiplier:1 constant:5];
        [manualConstraints addObject:b1_top];

        NSLayoutConstraint* b1_left = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeLeading multiplier:1 constant:5];
        [manualConstraints addObject:b1_left];

        NSLayoutConstraint* b1_right = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTrailing multiplier:1 constant:-5];
        [manualConstraints addObject:b1_right];
        NSLayoutConstraint* b1_bottom = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTop multiplier:1 constant:-10];
        [manualConstraints addObject:b1_bottom];

        [subview layoutIfNeeded];
        [scrollView addConstraints:manualConstraints];
        lastview=subview;
    }
    else{

        NSLayoutConstraint* b1_top = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTop multiplier:1 constant:5];
        [manualConstraints addObject:b1_top];

        NSLayoutConstraint* b1_left = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:lastview attribute:NSLayoutAttributeLeading multiplier:1 constant:5];
        [manualConstraints addObject:b1_left];

        NSLayoutConstraint* b1_right = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTrailing multiplier:1 constant:-5];
        [manualConstraints addObject:b1_right];
        NSLayoutConstraint* b1_bottom = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTop multiplier:1 constant:-10];
        [manualConstraints addObject:b1_bottom];

        [subview layoutIfNeeded];
        [scrollView addConstraints:manualConstraints];
        lastview=subview;

    }
}

scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * arrayData.count, mainFrame.size.height/2);

self.pageControl.currentPage = 0;
self.pageControl.numberOfPages = arrayData.count;

 pageControlBeingUsed = NO;
}

-(UIColor *)getRandomColor{
    int r = arc4random() % 255;
    int g = arc4random() % 255;
    int b = arc4random() % 255;
    return [UIColor colorWithRed:(r/255.0) green:(g/255.0) blue:(b/255.0) alpha:1.0];
}

Right now i am getting any subviews,

but if i change orientation it will give incorrect result, So how can i give NSLayoutConstraint for subviews of scrollview ?

EDIT

After adding NSLayoutConstraint subviews are not shown. I am just missing some constraint , please correct me in setting constraints dynamically.

My Source Code is here , Please Help Me. Thank you. And Sorry for bad grammar.

Cœur
  • 32,421
  • 21
  • 173
  • 232
  • What do you mean by "incorrect result" ? – Tancrede Chazallet Feb 21 '14 at 13:03
  • @AncAinu:pageControl goes out of view. –  Feb 21 '14 at 13:35
  • First of all, if you do `AutoLayout` programmatically, I advice you to [use this great Framework](https://github.com/iMartinKiss/KeepLayout) it will make your life so much easier and your code so much readable ;) – Tancrede Chazallet Feb 21 '14 at 13:51
  • @AncAinu: Thanks for your suggestion, i dont want to use some other classes for this. plese can you help with my current implement, i'm just missing somethong little. –  Feb 21 '14 at 13:54
  • Do you see any information show up in the debug console when rotating the device? E.g. Unable to simultaneously satisfy constraints. Usually the debug console will give you some hint as to why the views are not being displayed correctly. Also, you should be setting **translatesAutoresizingMaskIntoConstraints = NO** on the subviews. – Jonathan Feb 21 '14 at 14:39
  • @Jonathan: yes i have set `translatesAutoresizingMaskIntoConstraints=NO` and in console i am not able to get subview frame , i also have set `layoutIfNeeded` for frame but till it show so many warnings in console, look at my sourse code . –  Feb 21 '14 at 14:42
  • @Jonathan: Look my NSLayoutConstraint for subviews in loop, i think i'm doing some silly mistake. –  Feb 21 '14 at 14:44

4 Answers4

10

In my experience with AutoLayout (that I use programmatically too). You should not add views directly to your UIScrollView.

You should do one UIView and only one, that you add as subview of your UIScrollView.

Once this is done, you can add all of your subviews to this UIView.

Everything is explained in detail here : Apple iOS Technical Note TN2154

Tancrede Chazallet
  • 6,547
  • 3
  • 35
  • 59
  • Yes I'm doing in this way i have `UIView > UIScrollview` and in scrollview also i'm adding one view, and in reference link has single view, i have to add multiple views into uiscrollview. –  Feb 21 '14 at 14:04
  • 1
    It's not what I read in your code, you do `[scrollView addSubview:subview];` in a `for` statement, so you add many views to your `UIScrollView` – Tancrede Chazallet Feb 21 '14 at 14:07
  • in refer link they have used `NSLayoutConstraint` with **constraintsWithVisualFormat** , i am not able to do in my case, so i have used other NSLayoutConstraint way. –  Feb 21 '14 at 14:07
  • 1
    i have to add views in uiscrollview because i want funcationality like `iPhone` Photos app, but with pagecontrol.. SO tell me how can i achieve gallery + pagecontrol functionality without adding subviews to scrollview. –  Feb 21 '14 at 14:09
  • 3
    Maybe you can read carefully my answer... I explain you need to do `UIScrollView > UIView > UIView[](your photos)`. And if I were you, I would do a `UICollectionView`with horizontal scroll and paging enabled, it should do what you want in a simpler way ;) (But I never tried to have an horizontal `UICollectionView` I admit) – Tancrede Chazallet Feb 21 '14 at 14:12
  • Thanks for replay, and soryy because still i'm not getting what you say with `UIScrollView > UIView > UIView[](your photos)` can you give some refer link for that? or example or some code?\ –  Feb 21 '14 at 14:16
  • And i also **don't** have much knowledge about `UICollectionView`, if it is possible with my current implementation `UIScrollview + UIPagecontrol + AutolayOut`? –  Feb 21 '14 at 14:18
  • `UICollectionView` is like `UITableVIew` but it does cells (square ones) so to display photos it's the best way I think. For the solution I give you, it's in the link I gave. But it's the *mixed approach*. It's not pure AutoLayout, but since you say you can't do the other approach, it's the best way to achieve your goal. – Tancrede Chazallet Feb 21 '14 at 14:22
  • is it done with NSConstraint Programatically ? I need autolayout programatically, and i am creating this not only for Photos, it is also used for other purpose also, so i guess i am not go with collectionView. i havent experience with collectionView. –  Feb 21 '14 at 14:28
  • You just use `autoresizing mask`for the intermediate `UIView` and you use AutoLayout like you want for your Photos etc. inside. – Tancrede Chazallet Feb 21 '14 at 14:30
  • Thnks again but in my case it will not so useful, i need to do with `NSLayoutConstraint` only, i know it is possible , but dont know how to set that in loop. –  Feb 21 '14 at 14:33
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/48072/discussion-between-anc-ainu-and-user203108) – Tancrede Chazallet Feb 21 '14 at 14:33
  • Thank you, this technical note explains it. I used approach 1 and it works fine! – tuttu47 Oct 29 '15 at 09:46
6

Here is a SO answer has explained how to do this with auto layout, he has explain perfectly , In here there is vertically textfields are there But in your case it is you have to set Horizontal views constraints.

Alternative

Rather that setting constraints you can set just frame of the subview and set it in Scrollview, And based on orientation you can change frames of the scrolview's subviews.

Your setData Method like,

-(void)setData{

    [self layoutIfNeeded];
    CGRect mainFrame=scrollView.frame;
    CGRect frame;
    for (int i=0; i<arrayData.count ; i++)
    {
        CGRect frame;
        frame.origin.x = scrollView.frame.size.width * i;
        frame.origin.y = 0;
        frame.size = scrollView.frame.size;

        frame.origin=CGPointMake(0, 0);
        UIView *subview = [[UIView alloc]initWithFrame:frame];
        subview.backgroundColor = [self getRandomColor];
        [scrollView addSubview:subview];
    }
    scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * arrayData.count, mainFrame.size.height/2);
}

Now you using NSNotificationCenter you can get notify when device orientation chaged, so in this selector method of it call your setData method,

[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(setData)
                                                 name:UIDeviceOrientationDidChangeNotification
                                               object:nil];

Now in you setData method you need remove all subviews because when device changes Orientation it will add new views to your scrollview, so remove all subview from Scrollview before setting its frame,

        [scrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];

Make sure you are removing observer from your class like,

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
Community
  • 1
  • 1
Toseef Khilji
  • 16,458
  • 10
  • 78
  • 115
5

I know that the problem has been solved. and i hope that this solution my help for some people so i am posting it.

Below code is for adding the scrollview to the uiviewcontroller

  self.scrollView = UIScrollView()
    self.scrollView.backgroundColor = UIColor.greenColor()
    self.scrollView.setTranslatesAutoresizingMaskIntoConstraints(false)
    self.scrollView.scrollEnabled=true
    self.scrollView.pagingEnabled = true
    self.view.addSubview(self.scrollView)

    self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[scrollView]|", options: NSLayoutFormatOptions(0), metrics: nil, views: ["scrollView":self.scrollView]))

    self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[scrollView]|", options: NSLayoutFormatOptions(0), metrics: nil, views: ["scrollView":self.scrollView]))

After added the scrollview and add the subviews/images like this(this is an example for images showing in full size of scrollview like in photos app )

var prev:UIImgeView?

        for var index = 0; index < self.images.count; ++index {
            var iview = UIImgeView()
            iview.setTranslatesAutoresizingMaskIntoConstraints(false)
            self.scrollView.addSubview(iview)
            var image = self.images.objectAtIndex(index) as UIImage
            iview.image = image
            if (index == 0){
                self.scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[iview(==scrollView)]", options: NSLayoutFormatOptions(0), metrics: nil, views: ["iview":iview,"scrollView":self.scrollView]))
                prev = iview

            }
            else{
                self.scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[prev][iview(==prev)]", options: NSLayoutFormatOptions(0), metrics: nil, views: ["iview":iview,"prev":prev!]))
                prev = iview
            }
            self.scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[iview(==scrollView)]|", options: NSLayoutFormatOptions(0), metrics: nil, views: ["iview":iview,"scrollView":self.scrollView]))

            if (index == self.images.count-1){
                self.scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[prev]|", options: NSLayoutFormatOptions(0), metrics: nil, views: ["prev":prev!]))

            }

        }
sateesh
  • 477
  • 4
  • 17
0

If you want your TKScroller fixed to the center and support orientation changes, you can simply put the following code in your init

self.autoresizingMask = UIViewAutoresizingFlexibleWidth;

and you may need to check all your subview's of TKScroller. If you don't like autosize , you can set (one of the three)

self.autoresizingMask = UIViewAutoresizingFlexibleRightMargin;
self.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
self.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin;
Baoyu
  • 44
  • 4
  • That's only good for backwards compatibility sake (and using `setTranslatesAutoresizingMaskIntoConstraints:NO`), but I don't think it's what OP wants. – Can Feb 24 '14 at 11:49