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];
}
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);
}
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
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()
Merci à IOS Rocks et CularBytes pour les pistes sur ce sujet. J'ai trouvé deux problèmes (pour moi) avec les solutions ci-dessus:
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()
.
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];
}
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];
}
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;
});
}
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
}
}