Есть ли способ сделать UIScrollView
автоматическую настройку высоты (или ширины) содержимого, которое он прокручивает?
Что-то вроде:
[scrollView setContentSize:(CGSizeMake(320, content.height))];
Есть ли способ сделать UIScrollView
автоматическую настройку высоты (или ширины) содержимого, которое он прокручивает?
Что-то вроде:
[scrollView setContentSize:(CGSizeMake(320, content.height))];
Лучший метод, с которым я когда-либо сталкивался, обновлял размер содержимого UIScrollView
на основе его вложенных подпредставлений:
Objective-C
CGRect contentRect = CGRectZero;
for (UIView *view in self.scrollView.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
self.scrollView.contentSize = contentRect.size;
стриж
var contentRect = CGRect.zero
for view in mainScrollView.subviews {
contentRect = contentRect.union(view.frame)
}
mainScrollView.contentSize = contentRect.size
UIScrollView не знает высоту своего контента автоматически. Вы должны рассчитать высоту и ширину для себя
Сделайте это с чем-то вроде
CGFloat scrollViewHeight = 0.0f;
for (UIView* view in scrollView.subviews)
{
scrollViewHeight += view.frame.size.height;
}
[scrollView setContentSize:(CGSizeMake(320, scrollViewHeight))];
Но это работает только в том случае, если взгляды ниже друг друга. Если у вас есть вид рядом друг с другом, вам нужно добавить только высоту, если вы не хотите, чтобы содержимое скроллера больше, чем оно есть на самом деле.
Установите translatesAutoresizingMaskIntoConstraints
в NO
для всех рассмотренных видов.
Расположите и измените вид прокрутки с ограничениями, внешними по отношению к просмотру прокрутки.
Используйте ограничения для размещения подвью в представлении прокрутки, , чтобы убедиться, что ограничения связаны со всеми четырьмя краями вида прокрутки и не полагаются на представление прокрутки, чтобы получить их размер.
Источник: https://developer.apple.com/library/ios/technotes/tn2154/_index.html
Я добавил это в ответ Espuz и JCC. Он использует позицию y в подзонах и не включает полосы прокрутки. Изменить Использует нижнюю часть видимого нижнего подвид.
+ (CGFloat) bottomOfLowestContent:(UIView*) view
{
CGFloat lowestPoint = 0.0;
BOOL restoreHorizontal = NO;
BOOL restoreVertical = NO;
if ([view respondsToSelector:@selector(setShowsHorizontalScrollIndicator:)] && [view respondsToSelector:@selector(setShowsVerticalScrollIndicator:)])
{
if ([(UIScrollView*)view showsHorizontalScrollIndicator])
{
restoreHorizontal = YES;
[(UIScrollView*)view setShowsHorizontalScrollIndicator:NO];
}
if ([(UIScrollView*)view showsVerticalScrollIndicator])
{
restoreVertical = YES;
[(UIScrollView*)view setShowsVerticalScrollIndicator:NO];
}
}
for (UIView *subView in view.subviews)
{
if (!subView.hidden)
{
CGFloat maxY = CGRectGetMaxY(subView.frame);
if (maxY > lowestPoint)
{
lowestPoint = maxY;
}
}
}
if ([view respondsToSelector:@selector(setShowsHorizontalScrollIndicator:)] && [view respondsToSelector:@selector(setShowsVerticalScrollIndicator:)])
{
if (restoreHorizontal)
{
[(UIScrollView*)view setShowsHorizontalScrollIndicator:YES];
}
if (restoreVertical)
{
[(UIScrollView*)view setShowsVerticalScrollIndicator:YES];
}
}
return lowestPoint;
}
Вот признанный ответ в быстром тем, кто слишком ленив, чтобы преобразовать его:)
var contentRect = CGRectZero
for view in self.scrollView.subviews {
contentRect = CGRectUnion(contentRect, view.frame)
}
self.scrollView.contentSize = contentRect.size
Здесь адаптация Swift 3 @leviatan:
EXTENSION
import UIKit
extension UIScrollView {
func resizeScrollViewContentSize() {
var contentRect = CGRect.zero
for view in self.subviews {
contentRect = contentRect.union(view.frame)
}
self.contentSize = contentRect.size
}
}
ИСПОЛЬЗОВАНИЕ
scrollView.resizeScrollViewContentSize()
Очень проста в использовании!
Следующее расширение будет полезно в Swift.
extension UIScrollView{
func setContentViewSize(offset:CGFloat = 0.0) {
// dont show scroll indicators
showsHorizontalScrollIndicator = false
showsVerticalScrollIndicator = false
var maxHeight : CGFloat = 0
for view in subviews {
if view.isHidden {
continue
}
let newHeight = view.frame.origin.y + view.frame.height
if newHeight > maxHeight {
maxHeight = newHeight
}
}
// set content size
contentSize = CGSize(width: contentSize.width, height: maxHeight + offset)
// show scroll indicators
showsHorizontalScrollIndicator = true
showsVerticalScrollIndicator = true
}
}
Логика одинакова с данными ответами. Тем не менее, он пропускает скрытые представления в UIScrollView
и вычисление выполняется после скрытых указателей прокрутки.
Кроме того, есть необязательный параметр функции, и вы можете добавить значение смещения, передав параметр в функцию.
Отличное и лучшее решение от @leviathan. Просто перевести на быстрый подход с использованием FP (функционального программирования).
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect(), {
CGRectUnion($0, $1.frame)
}.size
Вы можете получить высоту содержимого внутри UIScrollView, посчитав, какой ребенок "достигает дальнейших". Чтобы вычислить это, вы должны принять во внимание начало Y (начало) и высоту элемента.
float maxHeight = 0;
for (UIView *child in scrollView.subviews) {
float childHeight = child.frame.origin.y + child.frame.size.height;
//if child spans more than current maxHeight then make it a new maxHeight
if (childHeight > maxHeight)
maxHeight = childHeight;
}
//set content size
[scrollView setContentSize:(CGSizeMake(320, maxHeight))];
Делая вещи таким образом, элементы (subviews) не должны быть уложены непосредственно друг под другом.
Я придумал другое решение, основанное на решении @emenegro
NSInteger maxY = 0;
for (UIView* subview in scrollView.subviews)
{
if (CGRectGetMaxY(subview.frame) > maxY)
{
maxY = CGRectGetMaxY(subview.frame);
}
}
maxY += 10;
[scrollView setContentSize:CGSizeMake(scrollView.frame.size.width, maxY)];
В принципе, мы выясняем, какой элемент наиболее удален в представлении и добавляет отладку 10px на дно.
Так как scrollView может иметь другие scrollViews или другое дерево inDepth subViews, то рекурсивно работать рекурсивно.
Swift 2
extension UIScrollView {
//it will block the mainThread
func recalculateVerticalContentSize_synchronous () {
let unionCalculatedTotalRect = recursiveUnionInDepthFor(self)
self.contentSize = CGRectMake(0, 0, self.frame.width, unionCalculatedTotalRect.height).size;
}
private func recursiveUnionInDepthFor (view: UIView) -> CGRect {
var totalRect = CGRectZero
//calculate recursevly for every subView
for subView in view.subviews {
totalRect = CGRectUnion(totalRect, recursiveUnionInDepthFor(subView))
}
//return the totalCalculated for all in depth subViews.
return CGRectUnion(totalRect, view.frame)
}
}
Использование
scrollView.recalculateVerticalContentSize_synchronous()
Или просто выполните:
int y = CGRectGetMaxY(((UIView*)[_scrollView.subviews lastObject]).frame); [_scrollView setContentSize:(CGSizeMake(CGRectGetWidth(_scrollView.frame), y))];
(Это решение было добавлено мной в качестве комментария на этой странице. Получив 19 голосов за этот комментарий, я решил добавить это решение в качестве официального ответа на благо сообщества!)
Размер зависит от содержимого, загруженного внутри него, и параметров отсечения. Если это текстовое представление, то это также зависит от обертывания, количества строк текста, размера шрифта и т.д. И т.д. Вы почти невозможно вычислить себя. Хорошей новостью является то, что она вычисляется после загрузки представления и в viewWillAppear. До этого все неизвестные и размер контента будут такими же, как размер кадра. Но в методе viewWillAppear и после (например, viewDidAppear) размер содержимого будет фактическим.
Копирование кода Richy Я создал настраиваемый класс UIScrollView, который автоматизирует полное изменение содержимого!
SBScrollView.h
@interface SBScrollView : UIScrollView
@end
SBScrollView.m:
@implementation SBScrollView
- (void) layoutSubviews
{
CGFloat scrollViewHeight = 0.0f;
self.showsHorizontalScrollIndicator = NO;
self.showsVerticalScrollIndicator = NO;
for (UIView* view in self.subviews)
{
if (!view.hidden)
{
CGFloat y = view.frame.origin.y;
CGFloat h = view.frame.size.height;
if (y + h > scrollViewHeight)
{
scrollViewHeight = h + y;
}
}
}
self.showsHorizontalScrollIndicator = YES;
self.showsVerticalScrollIndicator = YES;
[self setContentSize:(CGSizeMake(self.frame.size.width, scrollViewHeight))];
}
@end
Как использовать:
Просто импортируйте файл .h в контроллер просмотра и
объявите экземпляр SBScrollView вместо обычного UIScrollView.
Задайте размер динамического содержимого следующим образом.
self.scroll_view.contentSize = CGSizeMake(screen_width,CGRectGetMaxY(self.controlname.frame)+20);
Для swift4 с использованием уменьшите:
self.scrollView.contentSize = self.scrollView.subviews.reduce(CGRect.zero, {
return $0.union($1.frame)
}).size
это действительно зависит от контента: content.frame.height может дать вам то, что вы хотите? Зависит от того, является ли контент единственной вещью или коллекцией вещей.
Я также нашел ответ leviathan, чтобы работать лучше всего. Однако он подсчитывал странную высоту. При переходе через subviews, если в scrollview установлены индикаторы прокрутки, они будут находиться в массиве subviews. В этом случае решение состоит в том, чтобы временно отключить индикаторы прокрутки перед циклом, а затем восстановить их предыдущую настройку видимости.
-(void)adjustContentSizeToFit
является общедоступным методом в пользовательском подклассе UIScrollView.
-(void)awakeFromNib {
dispatch_async(dispatch_get_main_queue(), ^{
[self adjustContentSizeToFit];
});
}
-(void)adjustContentSizeToFit {
BOOL showsVerticalScrollIndicator = self.showsVerticalScrollIndicator;
BOOL showsHorizontalScrollIndicator = self.showsHorizontalScrollIndicator;
self.showsVerticalScrollIndicator = NO;
self.showsHorizontalScrollIndicator = NO;
CGRect contentRect = CGRectZero;
for (UIView *view in self.subviews) {
contentRect = CGRectUnion(contentRect, view.frame);
}
self.contentSize = contentRect.size;
self.showsVerticalScrollIndicator = showsVerticalScrollIndicator;
self.showsHorizontalScrollIndicator = showsHorizontalScrollIndicator;
}
Я думаю, что это может быть аккуратный способ обновления размера представления содержимого UIScrollView.
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 + 20)
contentSize = newSize
}
}
почему не одна строка кода?
_yourScrollView.contentSize = CGSizeMake(0, _lastView.frame.origin.y + _lastView.frame.size.height);