web-dev-qa-db-fra.com

Comment définir la taille du contenu de UIScrollView de manière dynamique

J'ai une question à propos de UIScrollview.

L’histoire est que j’ai une UIView nommée ChartsView que je re-dessine moi-même par la méthode de substitution drawRect(). Le contenu du dessin a été généré dynamiquement. Donc, je ne connais pas sa taille avant l'exécution. La question est de savoir comment/où puis-je définir dynamiquement la taille du contenu de sa super vue (scrollView)? Une idée à ce sujet?

    - (void)viewDidLoad
    {
        [super viewDidLoad];

// not this way. it's fixed size.....
        ChartsView *chartsView = [[ChartsView alloc]initWithFrame:CGRectMake(0, 0, 320, 800)]; 

        self.scrollView.contentSize = chartsView.frame.size;

        [self.scrollView addSubview:chartsView];

    }
25
Roger Lee

Un autre moyen facile

- (void)viewDidLoad
{
    float sizeOfContent = 0;
    UIView *lLast = [scrollView.subviews lastObject];
    NSInteger wd = lLast.frame.Origin.y;
    NSInteger ht = lLast.frame.size.height;

    sizeOfContent = wd+ht;

    scrollView.contentSize = CGSizeMake(scrollView.frame.size.width, sizeOfContent);
}
58
IOS Rocks

Swift (2.0)

@IBOutlet weak var btnLatestButton: UIButton!

override func viewDidLoad() {
    super.viewDidLoad()

    let height = btnLatestButton.frame.size.height
    let pos = btnLatestButton.frame.Origin.y
    let sizeOfContent = height + pos + 10
    scrollview.contentSize.height = sizeOfContent

}

Au-dessus des cours, c’est quand vous avez juste un nombre fixe de vues sur votre scrollview . La méthode IOS Rocks est disponible mais n’était pas bonne pour moi, elle a créé plus d’espace que nécessaire.

    let lastView : UIView! = scrollview.subviews.last
    let height = lastView.frame.size.height
    let pos = lastView.frame.Origin.y
    let sizeOfContent = height + pos + 10
    scrollview.contentSize.height = sizeOfContent
6
CularBytes

Il n'est pas garanti à 100% que le dernier objet du tableau scrollView.subviews retournera l'objet y-Origin le plus élevé de votre vue de défilement. Le tableau de sous-vues est organisé par Z-Index (le dernier objet du tableau de sous-vues sera celui qui sera empilé le plus haut et sera la sous-vue la plus haute dans les sous-vues de la vue de défilement. Au lieu d'utiliser une fonction de tri de base pour parcourir les sous-vues et obtenir l'objet avec la plus haute origine y.

Voici une fonction de base de Swift 3 qui peut le faire: 

func calculateContentSize(scrollView: UIScrollView) -> CGSize {
    var topPoint = CGFloat()
    var height = CGFloat()

    for subview in scrollView.subviews {
        if subview.frame.Origin.y > topPoint {
            topPoint = subview.frame.Origin.y
            height = subview.frame.size.height
        }
    }
    return CGSize(width: scrollView.frame.size.width, height: height + topPoint)
}

Utilisation (dans viewDidLayoutSubviews ou chaque fois que la taille du contenu est mise à jour): 

scrollView.contentSize = calculateContentSize(scrollView: scrollView)

MISE À JOUR Swift 4

Voici une version plus consise dans Swift 4

extension UIScrollView {
    func updateContentView() {
        contentSize.height = subviews.sorted(by: { $0.frame.maxY < $1.frame.maxY }).last?.frame.maxY ?? contentSize.height
    }
}

Usage:

myScrollView.updateContentView()
4
Charlton Provatas

Merci à IOS Rocks et CularBytes pour les pistes sur ce sujet. J'ai trouvé deux problèmes (pour moi) avec les solutions ci-dessus:

  1. J'ai toujours un conteneur UIView comme le seul enfant de mon UIScrollView, je devais donc mettre à jour la façon dont je cherchais la dernière vue de cet enfant UIView (voir ci-dessous).
  2. Je décale mon contenu dans UIScrollView et, en tant que tel, je dois calculer la position absolue de cette dernière UIView (donc, par rapport à la fenêtre et non à la vue parent)

De plus, j'utilise autolayout pour épingler les côtés de UIScrollView, je n'ai donc pas à m'inquiéter de la largeur (comme CularBytes).

Voici ce que je propose et fonctionne (dans Swift 3.0):

func setScrollViewContentSize() {

    var height: CGFloat
    let lastView = self.myScrollView.subviews[0].subviews.last!
    print(lastView.debugDescription) // should be what you expect

    let lastViewYPos = lastView.convert(lastView.frame.Origin, to: nil).y  // this is absolute positioning, not relative
    let lastViewHeight = lastView.frame.size.height

    // sanity check on these
    print(lastViewYPos)
    print(lastViewHeight)

    height = lastViewYPos + lastViewHeight

    print("setting scroll height: \(height)")

    myScrollView.contentSize.height = height
}

J'appelle cela dans ma méthode viewDidAppear().

3
the_dude_abides

Essaye ça - 

- (void)viewDidLoad
    {
        [super viewDidLoad];

// not this way. it's fixed size.....
        ChartsView *chartsView = [[ChartsView alloc]initWithFrame:CGRectMake(0, 0, 320, 800)]; 

        //self.scrollView.contentSize = chartsView.frame.size;
        [self.scrollView setContentSize:CGSizeMake(chartsView.frame.size.width, chartsView.frame.size.height)];
        [self.scrollView addSubview:chartsView];

    }
1
Abhishek Mishra

essaye ça 

- (void)viewDidLoad
        {
            [super viewDidLoad];

    // not this way. it's fixed size.....
            ChartsView *chartsView = [[ChartsView alloc]initWithFrame:CGRectMake(0, 0, 320, 800)]; 

            self.scrollView.contentSize = chartsView.frame.size;
            [self.scrollView setNeedsDisplay];
            [self.scrollView addSubview:chartsView];

    }
1
MrWaqasAhmed

Calculer UIScrollview contentSize dynamiquement (en fonction du cadre des sous-vues)

Rapide:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    DispatchQueue.main.async {
        var contentRect = CGRect.zero

        for view in self.scrollView.subviews {
           contentRect = contentRect.union(view.frame)
        }

        self.scrollView.contentSize = contentRect.size
    }
}

Objectif c:

 - (void)viewDidLayoutSubviews {
     [super viewDidLayoutSubviews];

     dispatch_async(dispatch_get_main_queue(), ^ {
                        CGRect contentRect = CGRectZero;

                        for(UIView *view in scrollView.subviews)
                           contentRect = CGRectUnion(contentRect,view.frame);

                           scrollView.contentSize = contentRect.size;
                       });
}
0
Karen Hovhannisyan

Ceci est une extension écrite sur Swift 3

extension UIScrollView {
    func updateContentViewSize() {
        var newHeight: CGFloat = 0
        for view in subviews {
            let ref = view.frame.Origin.y + view.frame.height
            if ref > newHeight {
                newHeight = ref
            }
        }
        let oldSize = contentSize
        let newSize = CGSize(width: oldSize.width, height: newHeight + 100)
        contentSize = newSize
    }
}
0
Bogdan Ustyak