So, i'm trying to add a button to bottom of the scrollView but position of the button not as expected, the button's position at the top of the scrollView when i scroll to top, here's my code :
lazy var scrollView : UIScrollView = {
let scrollV = UIScrollView()
scrollV.translatesAutoresizingMaskIntoConstraints = false
scrollV.alwaysBounceVertical = true
scrollV.delegate = self
scrollV.autoresizingMask = [.flexibleWidth, .flexibleHeight]
return scrollV
}()
in viewDidLoad :
view.addSubview(scrollView)
scrollView.topAnchor.constraint(equalTo: self.topBar.bottomAnchor).isActive = true
scrollView.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
scrollView.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
scrollView.contentSize = CGSize(width: self.view.frame.width, height: 1000)
finally, I add the button to the scrollView :
scrollView.addSubview(myButton)
myButton.centerXAnchor.constraint(equalTo: self.scrollView.centerXAnchor).isActive = true
myButton.bottomAnchor.constraint(equalTo: self.scrollView.bottomAnchor).isActive = true
myButton.widthAnchor.constraint(equalToConstant: 150).isActive = true
myButton.heightAnchor.constraint(equalToConstant: 50).isActive = true
Related
Usually, I would use SwiftUI's ScrollView, but in my edge case scenario, I need to use it as a UIScrollView in SwiftUI's UIViewRepresentable
struct CALayerScrollView: UIViewRepresentable {
func makeUIView(context: Context) -> some UIView {
var view = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width / 2, height: UIScreen.main.bounds.height / 2))
let scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
}()
let scrollViewContainer: UIStackView = {
let view = UIStackView()
view.axis = .vertical
view.spacing = 10
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let redView: UIView = {
let view = UIView()
view.heightAnchor.constraint(equalToConstant: 500).isActive = true
view.backgroundColor = .red
return view
}()
let blueView: UIView = {
let view = UIView()
view.heightAnchor.constraint(equalToConstant: 200).isActive = true
view.backgroundColor = .blue
return view
}()
let greenView: UIView = {
let view = UIView()
view.heightAnchor.constraint(equalToConstant: 1200).isActive = true
view.backgroundColor = .green
return view
}()
view.addSubview(scrollView)
scrollView.addSubview(scrollViewContainer)
scrollViewContainer.addArrangedSubview(redView)
scrollViewContainer.addArrangedSubview(blueView)
scrollViewContainer.addArrangedSubview(greenView)
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
scrollViewContainer.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
scrollViewContainer.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
scrollViewContainer.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
scrollViewContainer.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
// this is important for scrolling
scrollViewContainer.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
return view
}
func updateUIView(_ uiView: UIViewType, context: Context) { }
}
I've tried setting the viewAxis to .horizontal, but I still does not scroll laterally.
Any advices is appreciated. Thanks
You are setting the stack view axis to Vertical -- but you want Horizontal scrolling... so set it to .horizontal.
You are setting Height for each arranged subview, but you haven't set the Widths... so give them Widths.
You should constrain the scroll view's content to the scroll view's Content Layout Guide.
Because you're setting varying Heights, it's not quite clear if you want only horizontal scrolling... so this example ends up scrolling both directions:
struct TestView: View {
var body: some View {
VStack {
CALayerScrollView()
}
.frame(width: 240, height: 400)
.background(Color.yellow)
}
}
struct CALayerScrollView: UIViewRepresentable {
func makeUIView(context: Context) -> some UIView {
let view = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width / 2, height: UIScreen.main.bounds.height / 2))
let scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
}()
let scrollViewContainer: UIStackView = {
let view = UIStackView()
// Horizontal Stack View
view.axis = .horizontal
view.spacing = 10
// .top Alignment, because we're setting different heights for the subviews
view.alignment = .top
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let redView: UIView = {
let view = UIView()
view.heightAnchor.constraint(equalToConstant: 500).isActive = true
// also needs a width
view.widthAnchor.constraint(equalToConstant: 200).isActive = true
view.backgroundColor = .red
return view
}()
let blueView: UIView = {
let view = UIView()
view.heightAnchor.constraint(equalToConstant: 200).isActive = true
// also needs a width
view.widthAnchor.constraint(equalToConstant: 400).isActive = true
view.backgroundColor = .blue
return view
}()
let greenView: UIView = {
let view = UIView()
view.heightAnchor.constraint(equalToConstant: 1200).isActive = true
// also needs a width
view.widthAnchor.constraint(equalToConstant: 800).isActive = true
view.backgroundColor = .green
return view
}()
view.addSubview(scrollView)
scrollView.addSubview(scrollViewContainer)
scrollViewContainer.addArrangedSubview(redView)
scrollViewContainer.addArrangedSubview(blueView)
scrollViewContainer.addArrangedSubview(greenView)
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
// we want to constrain the scroll view *content* to the Content Layout Guide
let cg = scrollView.contentLayoutGuide
scrollViewContainer.leadingAnchor.constraint(equalTo: cg.leadingAnchor).isActive = true
scrollViewContainer.trailingAnchor.constraint(equalTo: cg.trailingAnchor).isActive = true
scrollViewContainer.topAnchor.constraint(equalTo: cg.topAnchor).isActive = true
scrollViewContainer.bottomAnchor.constraint(equalTo: cg.bottomAnchor).isActive = true
return view
}
func updateUIView(_ uiView: UIViewType, context: Context) { }
}
Should get you on your way...
So I've added a scrollview to my view controller programmatically and added some views.
func setupScrollView() {
view.addSubview(scrollView)
scrollView.addSubview(contentView)
scrollView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
contentView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
scrollView.contentSize = contentView.frame.size
}
func addUserAndFollowView(id: String) {
userAndFollow = UserPfAndFollow(id: id)
if let userAndFollow = userAndFollow {
userAndFollow.view.isUserInteractionEnabled = true
contentView.addSubview(userAndFollow.view)
self.contentView.bringSubviewToFront(userAndFollow.view)
userAndFollow.view.translatesAutoresizingMaskIntoConstraints = false
userAndFollow.view.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
userAndFollow.view.widthAnchor.constraint(equalTo: contentView.widthAnchor).isActive = true
userAndFollow.view.heightAnchor.constraint(equalToConstant: 100).isActive = true
}
}
func setImageViewConstraints() {
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.heightAnchor.constraint(equalToConstant: 300).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 300).isActive = true
imageView.centerXAnchor.constraint(equalTo: self.contentView.centerXAnchor).isActive = true
if let userAndFollow = userAndFollow?.view {
imageView.topAnchor.constraint(equalTo: userAndFollow.bottomAnchor, constant: 5).isActive = true
}
}
func addLabelConstraints() {
self.albumTitle?.translatesAutoresizingMaskIntoConstraints = false
self.albumDescription?.translatesAutoresizingMaskIntoConstraints = false
albumTitle?.numberOfLines = 2
albumDescription?.numberOfLines = 3
albumDescription?.adjustsFontSizeToFitWidth = false
albumTitle?.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 14).isActive = true
albumTitle?.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 10).isActive = true
albumTitle?.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor).isActive = true
albumTitle?.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 10).isActive = true
albumDescription?.lineBreakMode = .byTruncatingTail
albumDescription?.topAnchor.constraint(equalTo: albumTitle!.bottomAnchor, constant: 9).isActive = true
albumDescription?.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 10).isActive = true
albumDescription?.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor).isActive = true
}
All these views show up the way I want them to with the scrollview not scrolling but when I add this next view (which is a tableview in a view controller) at the bottom of the rest of my views it doesn't show up. Possibly why the scrollview isn't scrolling.
func addViewController() {
if let viewController = viewController {
contentView.addSubview(viewController.view)
setVCConstraints()
}
}
func setVCConstraints() {
viewController?.view.translatesAutoresizingMaskIntoConstraints = false
viewController?.view.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor).isActive = true
viewController?.view.topAnchor.constraint(equalTo: albumDescription!.bottomAnchor, constant: 7).isActive = true
viewController?.view.widthAnchor.constraint(equalTo: self.contentView.widthAnchor).isActive = true
}
What can I do to make this view appear and have my scrollview scroll all the way down this view controller and it's array content and no more or less?
Before you add the view, you have
contentView.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor).isActive = true
contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
scrollView.contentSize = contentView.frame.size
So, of course, the contentView has a size of the scrollView and thus will not scroll. It is the same size.
After you add the view, you have
viewController?.view.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor).isActive = true
viewController?.view.topAnchor.constraint(equalTo: albumDescription!.bottomAnchor, constant: 7).isActive = true
viewController?.view.widthAnchor.constraint(equalTo: self.contentView.widthAnchor).isActive = true
Note, above, that you define a top bottom and width -- there is no LEFT-TO-RIGHT indication where the viewController.view should start on the horizontal path. This can result in some VERY weird behaviors.
Yet, you STILL don't modify the contentView.contentSize to be any bigger than the scrollView size.
To make something scroll, you need the contentView.contentSize to be bigger than the frame.size.
I have UITextView:
private let descriptionView: UITextView = {
let view = UITextView()
view.translatesAutoresizingMaskIntoConstraints = false
view.bounces = true
view.textColor = UIColor.white
view.font = UIFont(name: Fonts.regular, size: 28)
view.isSelectable = true
view.isUserInteractionEnabled = true
view.panGestureRecognizer.allowedPressTypes = [NSNumber(value: UITouch.TouchType.indirect.rawValue)]
view.showsVerticalScrollIndicator = true
return view
}()
Added in another view
addSubview(descriptionView)
addConstraints([
descriptionView.leadingAnchor.constraint(equalTo: title.leadingAnchor),
descriptionView.topAnchor.constraint(equalTo: ratings.bottomAnchor, constant: 60),
descriptionView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -80),
descriptionView.bottomAnchor.constraint(equalTo: bottomAnchor)
])
isSelectable = true,
view.isUserInteractionEnabled = true.
View focuses great, but not scrolling.
Content height > textview height
Similar questions did't help
I have a custom view, i set it in parent like:
func setup(){
view.backgroundColor = .gray
view.addSubview(chartView)
chartView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
chartView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
chartView.topAnchor.constraint(equalTo: view.topAnchor, constant: statusAndNavigationBarHeight).isActive = true
chartView.heightAnchor.constraint(equalToConstant: Dimensions.chartHeight.value).isActive = true
}
Then in that view i tried to set up a scroll:
scroll = UIScrollView.init(frame: CGRect(x: 0.0, y: 0.0, width: scrollWidth(), // print 728.0
height: Double(Dimensions.chartHeight.value))) // print 400.0
scroll.isScrollEnabled = true
scroll.showsHorizontalScrollIndicator = true
addSubview(scroll)
}
And thats all, when i launch app i can't drag and scroll horizontally, in debug editor i can't see that it is scroll view here lying with large width.
The scrollView doesn't scroll with it's size , it needs a content that define it's content size for example
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let chartView = UIView()
chartView.translatesAutoresizingMaskIntoConstraints = false
chartView.backgroundColor = .red
view.backgroundColor = .gray
view.addSubview(chartView)
chartView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
chartView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
chartView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
chartView.heightAnchor.constraint(equalToConstant:200).isActive = true
let scroll = UIScrollView(frame: CGRect(x: 0.0,
y: 0.0,
width: UIScreen.main.bounds.size.width, // print 728.0
height: 200.0))
scroll.isScrollEnabled = true
scroll.showsHorizontalScrollIndicator = true
chartView.addSubview(scroll)
let www = UIView()
www.backgroundColor = .green
www.translatesAutoresizingMaskIntoConstraints = false
scroll.addSubview(www)
www.leftAnchor.constraint(equalTo: scroll.leftAnchor).isActive = true
www.rightAnchor.constraint(equalTo: scroll.rightAnchor).isActive = true
www.topAnchor.constraint(equalTo: scroll.topAnchor).isActive = true
www.bottomAnchor.constraint(equalTo: scroll.bottomAnchor).isActive = true
www.heightAnchor.constraint(equalToConstant:200).isActive = true
www.widthAnchor.constraint(equalTo: view.widthAnchor,multiplier:2.0).isActive = true
scroll.addSubview(www)
}
}
I'm trying add a subview to UIScrollView. I add scrollView, subView and set constraints bellow :
class ViewController: UIViewController {
let scrollView : UIScrollView = {
let scrollView = UIScrollView()
scrollView.backgroundColor = .yellow
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.alwaysBounceVertical = true
return scrollView
}()
let catImageView : UIImageView = {
let img = UIImageView()
img.translatesAutoresizingMaskIntoConstraints = false
img.backgroundColor = .white
return img
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
view.addSubview(scrollView)
scrollView.frame = self.view.bounds
scrollView.contentSize = CGSize(width: self.view.frame.width, height: 1000)
scrollView.addSubview(catImageView)
catImageView.centerXAnchor.constraint(equalTo: self.scrollView.centerXAnchor).isActive = true
catImageView.centerYAnchor.constraint(equalTo: self.scrollView.centerYAnchor).isActive = true
catImageView.widthAnchor.constraint(equalToConstant: 200).isActive = true
catImageView.heightAnchor.constraint(equalToConstant: 100).isActive = true
}
I builded and scrollView and subiew are disappear. I don't know why...
Then I trying add subview another way like this :
view.addSubview(catImageView)
catImageView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
catImageView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
catImageView.widthAnchor.constraint(equalToConstant: 200).isActive = true
catImageView.heightAnchor.constraint(equalToConstant: 100).isActive = true
It's still the same. Please explained to me why. Thank a lot
You should only set the translatesAutoresizingMaskIntoConstraints to false in case you are adding the constraints to the view. You've set the property on the scrollView to false, but used the frame, and not constraints. Remove the line:
scrollView.translatesAutoresizingMaskIntoConstraints = false // <- remove
and it should work.
Hope this helps! Good luck!