Giả sử tôi đã thêm nhiều lượt xem trong UIStackView có thể được hiển thị, làm cách nào tôi có thể tạo UIStackView
cuộn?
Giả sử tôi đã thêm nhiều lượt xem trong UIStackView có thể được hiển thị, làm cách nào tôi có thể tạo UIStackView
cuộn?
Câu trả lời:
Trong trường hợp bất cứ ai đang tìm kiếm một giải pháp mà không có mã , tôi đã tạo một ví dụ để thực hiện điều này hoàn toàn trong bảng phân cảnh, sử dụng Giao diện tự động.
Bạn có thể lấy nó từ github .
Về cơ bản, để tạo lại ví dụ (để cuộn dọc):
UIScrollView
, và đặt các ràng buộc của nó.UIStackView
vàoUIScrollView
Leading
, Trailing
, Top
và Bottom
nên bằng những từUIScrollView
Width
ràng buộc bằng nhau giữa UIStackView
và UIScrollView
.UIStackView
UIViews
đếnUIStackView
Đổi Width
lấy Height
ở bước 4 và đặt Axis
= Horizontal
ở bước 5, để có được UIStackView theo chiều ngang.
Hướng dẫn bố cục tự động của Apple bao gồm toàn bộ phần Làm việc với Chế độ xem cuộn . Một số đoạn có liên quan:
- Ghim các cạnh trên, dưới, đầu và cuối của chế độ xem nội dung vào các cạnh tương ứng của chế độ xem cuộn. Chế độ xem nội dung hiện xác định vùng nội dung của chế độ xem cuộn.
- (Tùy chọn) Để tắt cuộn ngang, đặt chiều rộng của chế độ xem nội dung bằng với chiều rộng của chế độ xem cuộn. Chế độ xem nội dung hiện lấp đầy chế độ xem cuộn theo chiều ngang.
- (Tùy chọn) Để tắt cuộn dọc, đặt chiều cao của chế độ xem nội dung bằng với chiều cao của chế độ xem cuộn. Chế độ xem nội dung hiện lấp đầy chế độ xem cuộn theo chiều ngang.
Hơn nữa:
Bố cục của bạn phải xác định đầy đủ kích thước của chế độ xem nội dung (trừ khi được xác định trong bước 5 và 6). Nhiều khi chế độ xem nội dung cao hơn chế độ xem cuộn, chế độ xem cuộn cho phép cuộn dọc. Khi chế độ xem nội dung rộng hơn chế độ xem cuộn, chế độ xem cuộn cho phép cuộn ngang.
Để tóm tắt, chế độ xem nội dung của chế độ xem cuộn (trong trường hợp này là chế độ xem ngăn xếp) phải được ghim vào các cạnh của nó và có chiều rộng và / hoặc chiều cao của nó bị hạn chế. Điều đó có nghĩa là nội dung của chế độ xem ngăn xếp phải bị hạn chế (trực tiếp hoặc gián tiếp) theo hướng mà trong đó việc cuộn được mong muốn, có thể có nghĩa là thêm một ràng buộc về chiều cao cho mỗi chế độ xem trong chế độ xem ngăn xếp cuộn theo chiều dọc, ví dụ. Sau đây là một ví dụ về cách cho phép cuộn dọc của chế độ xem cuộn chứa chế độ xem ngăn xếp:
// Pin the edges of the stack view to the edges of the scroll view that contains it
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
// Set the width of the stack view to the width of the scroll view for vertical scrolling
stackView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
Need constraints for: Y position or height.
Lỗi này chỉ biến mất nếu bạn đặt cả ràng buộc về chiều rộng và chiều cao cho chế độ xem ngăn xếp, vô hiệu hóa cuộn dọc. Mã này vẫn còn làm việc cho bạn?
Các ràng buộc trong câu trả lời được bình chọn hàng đầu ở đây có tác dụng với tôi và tôi đã dán một hình ảnh về các ràng buộc bên dưới, như được tạo trong bảng phân cảnh của tôi.
Tôi đã nhấn hai vấn đề mặc dù những người khác nên biết:
Sau khi thêm các ràng buộc tương tự như các câu trả lời được chấp nhận, tôi sẽ gặp lỗi tự động thanh toán màu đỏ Need constraints for: X position or width
. Điều này đã được giải quyết bằng cách thêm một UILabel dưới dạng một khung nhìn phụ của chế độ xem ngăn xếp.
Tôi đang thêm các cuộc phỏng vấn theo chương trình, vì vậy ban đầu tôi không có cuộc phỏng vấn nào trên bảng phân cảnh. Để loại bỏ các lỗi tự động thanh toán, hãy thêm một khung nhìn vào bảng phân cảnh, sau đó loại bỏ nó khi tải trước khi thêm các ràng buộc và giới hạn thực của bạn.
Ban đầu tôi đã cố gắng thêm UIButtons
vào UIStackView. Các nút và chế độ xem sẽ tải, nhưng chế độ xem cuộn sẽ không cuộn . Điều này đã được giải quyết bằng cách thêm UILabels
vào Stack View thay vì các nút. Sử dụng các ràng buộc tương tự, chế độ xem phân cấp này với các cuộn UILabels nhưng các UIButtons thì không.
Tôi đang bối rối bởi vấn đề này, như UIButtons làm dường như có một IntrinsicContentSize (được sử dụng bởi độ xem ngăn xếp). Nếu bất cứ ai biết tại sao các nút không hoạt động, tôi rất muốn biết tại sao.
Dưới đây là hệ thống phân cấp và các ràng buộc của tôi, để tham khảo:
Như Eik nói, UIStackView
và UIScrollView
chơi với nhau độc đáo, xem tại đây .
Điều quan trọng là UIStackView
xử lý chiều cao / chiều rộng thay đổi cho các nội dung khác nhau và UIScrollView
sau đó thực hiện tốt công việc cuộn / nảy nội dung đó:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.contentSize = CGSize(width: stackView.frame.width, height: stackView.frame.height)
}
Tôi đang tìm cách làm điều tương tự và tình cờ thấy bài đăng tuyệt vời này . Nếu bạn muốn thực hiện việc này bằng lập trình bằng cách sử dụng API neo, đây là cách nên làm.
Để tóm tắt, hãy nhúng của bạn UIStackView
vào trong UIScrollView
và đặt các ràng buộc neo của UIStackView
khớp với các ràng buộc của UIScrollView
:
stackView.leadingAnchor.constraintEqualToAnchor(scrollView.leadingAnchor).active = true
stackView.trailingAnchor.constraintEqualToAnchor(scrollView.trailingAnchor).active = true
stackView.bottomAnchor.constraintEqualToAnchor(scrollView.bottomAnchor).active = true
stackView.topAnchor.constraintEqualToAnchor(scrollView.topAnchor).active = true
stackView.widthAnchor.constraintEqualToAnchor(scrollView.widthAnchor).active = true
Có một cảnh toàn màn hình trống
Thêm chế độ xem cuộn. Điều khiển kéo từ chế độ xem cuộn sang chế độ xem cơ sở , thêm từ trái sang phải từ trên xuống dưới, tất cả đều bằng không.
Thêm chế độ xem ngăn xếp trong chế độ xem cuộn. Điều khiển kéo từ chế độ xem ngăn xếp sang chế độ xem cuộn , thêm từ trái sang phải từ trên xuống dưới, tất cả đều bằng không.
Đặt hai hoặc ba nhãn bên trong khung nhìn ngăn xếp.
Để rõ ràng, làm cho màu nền của nhãn màu đỏ. Đặt chiều cao nhãn là 100.
Bây giờ đặt chiều rộng của mỗi UILabel:
Đáng ngạc nhiên, điều khiển kéo từ UILabel
chế độ xem cuộn, không đến chế độ xem ngăn xếp và chọn độ rộng bằng nhau .
Lặp lại:
Nó đơn giản mà. Đó là bí mật.
Mẹo bí mật - Lỗi của Apple:
Nó sẽ không hoạt động với chỉ một mục! Thêm một vài nhãn để làm cho bản demo hoạt động.
Bạn đã hoàn tất.
Mẹo: Bạn phải thêm chiều cao cho mỗi mục mới . Mỗi mục trong bất kỳ chế độ xem ngăn xếp cuộn phải có kích thước nội tại (chẳng hạn như nhãn) hoặc thêm ràng buộc chiều cao rõ ràng.
Phương pháp thay thế:
Trong phần trên: đáng ngạc nhiên, đặt độ rộng của UILabels thành chiều rộng của chế độ xem cuộn (không phải dạng xem ngăn xếp).
Luân phiên ...
Vì vậy, bạn có hai lựa chọn:
hoặc là
Để rõ ràng, hãy thực hiện MỘT trong những phương pháp đó, KHÔNG làm cả hai.
Đối với cuộn ngang. Đầu tiên, tạo một UIStackView
và a UIScrollView
và thêm chúng vào chế độ xem của bạn theo cách sau:
let scrollView = UIScrollView()
let stackView = UIStackView()
scrollView.addSubview(stackView)
view.addSubview(scrollView)
Ghi nhớ để thiết lập translatesAutoresizingMaskIntoConstraints
để false
trên UIStackView
và UIScrollView
:
stackView.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
Để có được mọi thứ làm việc theo dõi, các neo dẫn đầu, trên và dưới UIStackView
phải bằng với các UIScrollView
neo:
stackView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
Nhưng neo chiều rộng của UIStackView
phải bằng hoặc lớn hơn chiều rộng của UIScrollView
neo:
stackView.widthAnchor.constraint(greaterThanOrEqualTo: scrollView.widthAnchor).isActive = true
Bây giờ neo của bạn UIScrollView
, ví dụ:
scrollView.heightAnchor.constraint(equalToConstant: 80).isActive = true
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor).isActive = true
scrollView.leadingAnchor.constraint(equalTo:view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo:view.trailingAnchor).isActive = true
Tiếp theo, tôi khuyên bạn nên thử các cài đặt sau cho UIStackView
căn chỉnh và phân phối:
topicStackView.axis = .horizontal
topicStackView.distribution = .equalCentering
topicStackView.alignment = .center
topicStackView.spacing = 10
Cuối cùng, bạn sẽ cần sử dụng addArrangedSubview:
phương pháp để thêm các cuộc phỏng vấn vào UIStackView của mình.
Một tính năng bổ sung mà bạn có thể tìm thấy hữu ích là vì UIStackView
được tổ chức trong vòng một UIScrollView
bây giờ bạn có quyền truy cập vào insets văn bản để làm cho mọi việc trông đẹp hơn chút.
let inset:CGFloat = 20
scrollView.contentInset.left = inset
scrollView.contentInset.right = inset
// remember if you're using insets then reduce the width of your stack view to match
stackView.widthAnchor.constraint(greaterThanOrEqualTo: topicScrollView.widthAnchor, constant: -inset*2).isActive = true
Chỉ cần thêm nó vào viewdidload
:
let insets = UIEdgeInsetsMake(20.0, 0.0, 0.0, 0.0)
scrollVIew.contentInset = insets
scrollVIew.scrollIndicatorInsets = insets
Bạn có thể thử ScrollableStackView : https://github.com/gurhub/ScrollableStackView
Đó là thư viện tương thích Objective-C và Swift. Nó có sẵn thông qua Cốc Cốc .
Mã mẫu (Swift)
import ScrollableStackView
var scrollable = ScrollableStackView(frame: view.frame)
view.addSubview(scrollable)
// add your views with
let rectangle = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 55))
rectangle.backgroundColor = UIColor.blue
scrollable.stackView.addArrangedSubview(rectangle)
// ...
Mã mẫu (Mục tiêu-C)
@import ScrollableStackView
ScrollableStackView *scrollable = [[ScrollableStackView alloc] initWithFrame:self.view.frame];
scrollable.stackView.distribution = UIStackViewDistributionFillProportionally;
scrollable.stackView.alignment = UIStackViewAlignmentCenter;
scrollable.stackView.axis = UILayoutConstraintAxisVertical;
[self.view addSubview:scrollable];
UIView *rectangle = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 55)];
[rectangle setBackgroundColor:[UIColor blueColor]];
// add your views with
[scrollable.stackView addArrangedSubview:rectangle];
// ...
Nếu bạn có một ràng buộc để căn giữa Stack View theo chiều dọc bên trong chế độ xem cuộn, chỉ cần xóa nó.
Ví dụ cho stackview / scrollview dọc (sử dụng EasyPeasy
cho autolayout):
let scrollView = UIScrollView()
self.view.addSubview(scrollView)
scrollView <- [
Edges(),
Width().like(self.view)
]
let stackView = UIStackView(arrangedSubviews: yourSubviews)
stackView.axis = .vertical
stackView.distribution = .fill
stackView.spacing = 10
scrollView.addSubview(stackView)
stackView <- [
Edges(),
Width().like(self.view)
]
Chỉ cần đảm bảo rằng mỗi chiều cao của khung nhìn của bạn được xác định!
Đầu tiên và quan trọng nhất là thiết kế chế độ xem của bạn, tốt nhất là trong một cái gì đó như Phác thảo hoặc có ý tưởng về những gì bạn muốn như một nội dung có thể cuộn.
Sau đó, tạo biểu mẫu miễn phí của trình điều khiển chế độ xem (chọn từ trình kiểm tra thuộc tính) và đặt chiều cao và chiều rộng theo kích thước nội dung bên trong của chế độ xem của bạn (sẽ được chọn từ trình kiểm tra kích thước).
Sau đó, trong trình điều khiển chế độ xem đặt chế độ xem cuộn và đây là logic mà tôi thấy rằng nó hoạt động gần như mọi lúc trong iOS (nó có thể yêu cầu đi qua tài liệu của lớp chế độ xem mà người ta có thể nhận được thông qua lệnh + nhấp vào lớp học đó hoặc thông qua googling)
Nếu bạn đang làm việc với hai hoặc nhiều chế độ xem thì trước tiên hãy bắt đầu với một chế độ xem, đã được giới thiệu trước đó hoặc nguyên thủy hơn và sau đó chuyển đến chế độ xem được giới thiệu sau hoặc hiện đại hơn. Vì vậy, ở đây vì chế độ xem cuộn đã được giới thiệu trước tiên, hãy bắt đầu với chế độ xem cuộn trước và sau đó chuyển đến chế độ xem ngăn xếp. Ở đây đặt các ràng buộc của chế độ xem cuộn xuống 0 theo mọi hướng nhìn siêu nhìn của nó. Đặt tất cả các chế độ xem của bạn trong chế độ xem cuộn này và sau đó đặt chúng vào chế độ xem ngăn xếp.
Trong khi làm việc với chế độ xem ngăn xếp
Trước tiên, bắt đầu với căn cứ (cách tiếp cận từ dưới lên), tức là, nếu bạn có nhãn, trường văn bản và hình ảnh trong chế độ xem của bạn, sau đó bố trí các chế độ xem này trước (bên trong chế độ xem cuộn) và sau đó đặt chúng vào chế độ xem ngăn xếp.
Sau đó tinh chỉnh thuộc tính của stack view. Nếu chế độ xem mong muốn vẫn không đạt được, thì hãy sử dụng chế độ xem ngăn xếp khác.
Sau khi thực hiện chế độ xem của bạn, đặt một ràng buộc giữa chế độ xem ngăn xếp mẹ và chế độ xem cuộn, trong khi ràng buộc chế độ xem ngăn xếp con với chế độ xem ngăn xếp mẹ. Hy vọng đến lúc này nó sẽ hoạt động tốt hoặc bạn có thể nhận được cảnh báo từ Xcode khi đưa ra đề xuất, hãy đọc những gì nó nói và thực hiện những điều đó. Hy vọng bây giờ bạn nên có một cái nhìn làm việc theo mong đợi của bạn :).
Đối với chế độ xem cuộn xem lồng nhau hoặc đơn phải được đặt chiều rộng cố định với chế độ xem gốc. Chế độ xem ngăn xếp chính nằm trong chế độ xem cuộn phải đặt cùng chiều rộng. [Chế độ xem cuộn của tôi dưới đây của Chế độ xem bỏ qua]
Thiết lập một ràng buộc Độ rộng bằng nhau giữa UIStackView và UIScrollView.
Nếu bất cứ ai tìm kiếm cuộn theo chiều ngang
func createHorizontalStackViewsWithScroll() {
self.view.addSubview(stackScrollView)
stackScrollView.translatesAutoresizingMaskIntoConstraints = false
stackScrollView.heightAnchor.constraint(equalToConstant: 85).isActive = true
stackScrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
stackScrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
stackScrollView.bottomAnchor.constraint(equalTo: visualEffectViews.topAnchor).isActive = true
stackScrollView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.topAnchor.constraint(equalTo: stackScrollView.topAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: stackScrollView.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: stackScrollView.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: stackScrollView.bottomAnchor).isActive = true
stackView.heightAnchor.constraint(equalTo: stackScrollView.heightAnchor).isActive = true
stackView.distribution = .equalSpacing
stackView.spacing = 5
stackView.axis = .horizontal
stackView.alignment = .fill
for i in 0 ..< images.count {
let photoView = UIButton.init(frame: CGRect(x: 0, y: 0, width: 85, height: 85))
// set button image
photoView.translatesAutoresizingMaskIntoConstraints = false
photoView.heightAnchor.constraint(equalToConstant: photoView.frame.height).isActive = true
photoView.widthAnchor.constraint(equalToConstant: photoView.frame.width).isActive = true
stackView.addArrangedSubview(photoView)
}
stackView.setNeedsLayout()
}
Đặt chế độ xem cuộn trên cảnh của bạn và kích thước nó để nó lấp đầy cảnh. Sau đó, đặt chế độ xem ngăn xếp bên trong chế độ xem cuộn và đặt nút thêm mục bên trong chế độ xem ngăn xếp. Ngay khi mọi thứ vào vị trí, đặt các ràng buộc sau:
Scroll View.Leading = Superview.LeadingMargin
Scroll View.Trailing = Superview.TrailingMargin
Scroll View.Top = Superview.TopMargin
Bottom Layout Guide.Top = Scroll View.Bottom + 20.0
Stack View.Leading = Scroll View.Leading
Stack View.Trailing = Scroll View.Trailing
Stack View.Top = Scroll View.Top
Stack View.Bottom = Scroll View.Bottom
Stack View.Width = Scroll View.Width
mã: Stack View.Width = Scroll View.Width
là chìa khóa.
Thêm một số quan điểm mới cho macOS Catalyst. Vì các ứng dụng macOS hỗ trợ thay đổi kích thước cửa sổ, có thể bạn UIStackView
sẽ chuyển từ trạng thái không thể kiểm soát sang trạng thái có thể cuộn hoặc ngược lại. Có hai điều tinh tế ở đây:
UIStackView
được thiết kế để phù hợp với tất cả các khu vực nó có thể.UIScrollView
sẽ cố gắng thay đổi kích thước giới hạn của nó để giải thích cho khu vực mới đạt được / bị mất bên dưới thanh điều hướng của bạn (hoặc thanh công cụ trong trường hợp ứng dụng macOS).Điều này không may sẽ tạo ra một vòng lặp vô hạn. Tôi không quen thuộc lắm UIScrollView
và với nó adjustedContentInset
, nhưng từ nhật ký của tôi trong layoutSubviews
phương thức của nó , tôi thấy hành vi sau:
UIScrollView
cố gắng thu hẹp giới hạn của nó (vì không cần khu vực bên dưới thanh công cụ).UIStackView
sauUIScrollView
không hài lòng, và quyết định khôi phục lại các giới hạn lớn hơn. Điều này cảm thấy rất kỳ lạ đối với tôi vì những gì tôi đang nhìn thấy từ nhật ký là vậy UIScrollView.bounds.height == UIStackView.bounds.height
.UIStackView
sauTôi nhận thấy rằng hai bước sẽ khắc phục vấn đề:
UIStackView.top
để UIScrollView.topMargin
.contentInsetAdjustmentBehavior
thành .never
.Ở đây tôi quan tâm đến một chế độ xem theo chiều dọc với sự tăng trưởng theo chiều dọc UIStackView
. Đối với một cặp ngang, thay đổi mã cho phù hợp.
Hy vọng nó sẽ giúp bất cứ ai trong tương lai. Không thể tìm thấy bất cứ ai đề cập đến điều này trên Internet và tôi đã mất khá nhiều thời gian để tìm hiểu chuyện gì đã xảy ra.