Auto layout with textview inside views [Swift] - swift

I'm trying to create two views inside a main view and these view are autoresized by a textView, I want to add first one view and then by clicking a button add the seconds but I have some errors.
But I don't want to put equal height constraint to the main view, it has to resize according to textviews inside its 2 subviews
Here's a snippet of my code and an image of what i mean:
#objc func buttonAction() {
print("action")
mainView.addSubview(secondView)
firstView.topAnchor.constraint(equalTo: mainView.topAnchor).isActive = false
// I've tried to disable it to change the topAnchor of firstView
NSLayoutConstraint.activate([
secondView.bottomAnchor.constraint(equalTo: firstView.topAnchor),
secondView.leadingAnchor.constraint(equalTo: mainView.leadingAnchor),
secondView.trailingAnchor.constraint(equalTo: mainView.trailingAnchor),
secondView.topAnchor.constraint(equalTo: mainView.topAnchor)
])
}
func addConstraints() {
NSLayoutConstraint.activate([
firstView.topAnchor.constraint(equalTo: mainView.topAnchor),
firstView.bottomAnchor.constraint(equalTo: mainView.bottomAnchor),
firstView.leadingAnchor.constraint(equalTo: mainView.leadingAnchor),
firstView.trailingAnchor.constraint(equalTo: mainView.trailingAnchor),
])
NSLayoutConstraint.activate([
mainView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
mainView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])
}
class View1: UIView { // the same as View2 class
lazy var textView: UITextView = {
let tv = UITextView()
tv.backgroundColor = .red
tv.isScrollEnabled = false
tv.font = UIFont(name: "Avenir", size: 16)
tv.text = "First"
tv.translatesAutoresizingMaskIntoConstraints = false
return tv
}()
init() {
super.init(frame: .zero)
setup()
}
required init?(coder: NSCoder) {
fatalError()
}
func setup() {
addSubview(textView)
textView.fillSuperview(padding: .init(top: 4, left: 4, bottom: 4, right: 4))
// fillSuperview() put 4 in top,left,right,bottom of superview
}
}
Here's an image of what I mean:

You need to save a reference to the firstView top constraint and deactivate that reference. You were trying to deactivate a new reference to the firstView top constraint.
class ViewController: UIViewController {
var firstViewTop: NSLayoutConstraint!
func addConstraints() {
firstViewTop = firstView.topAnchor.constraint(equalTo: mainView.topAnchor)
NSLayoutConstraint.activate([
firstViewTop,
firstView.bottomAnchor.constraint(equalTo: mainView.bottomAnchor),
firstView.leadingAnchor.constraint(equalTo: mainView.leadingAnchor),
firstView.trailingAnchor.constraint(equalTo: mainView.trailingAnchor),
])
NSLayoutConstraint.activate([
mainView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
mainView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])
}
#objc func buttonAction() {
mainView.addSubview(secondView)
firstViewTop.isActive = false
NSLayoutConstraint.activate([
secondView.bottomAnchor.constraint(equalTo: firstView.topAnchor),
secondView.leadingAnchor.constraint(equalTo: mainView.leadingAnchor),
secondView.trailingAnchor.constraint(equalTo: mainView.trailingAnchor),
secondView.topAnchor.constraint(equalTo: mainView.topAnchor)
])
}
}

Related

Disable Scrolling of UIScrollView on part of the ScrollView.frame

Hello hope everyone is safe. I have a ViewController(vc) which contains a UIScrollView(scrlView). The scrlView contains two other ViewControllers(vc1 & vc2). On the vc1 I have a button which pressed adds a subview(subViewVc1) to vc1. In order to not be shown on the other scrlView page on delegation begin dragging I remove the subviewVc1. The problem I have is that I can't deactivate scrolling of the scrlView where the subViewVc1 frame is.
I have tried multiple ways as subclassing the scrollview as modifying touchesBegan, but touchesBegan recognises a touch, if the user perform even a small drag the gesture is not recognised anymore. I have tried to add a swipe gesture recogniser but I realised it interfere with the scrollview gesture.
Anybody has any idea on what to do?
Here is one way this can be achieved, instead of disabling a specific frame, you can disable interaction on over a specific view:
SubClass the UIView you add on button tap with no real implementation but just for recognition - you can also use view tags if you prefer
SubClass the UIScrollView and implement touchesShouldCancel to cancel scrolling when interacting with a specific view
Set scrollView.delaysContentTouches = false
Implementation
First I tried to recreate your situation, I created the child view controller class with a button which will go into the scrollview:
class ChildVC: UIViewController
{
let button = UIButton(type: .system)
override func viewDidLoad()
{
super.viewDidLoad()
view.backgroundColor = .yellow
configureButton()
}
private func configureButton()
{
button.setTitle("Add View", for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self,
action: #selector(didTapAddView),
for: .touchUpInside)
view.addSubview(button)
view.addConstraints([
button.leadingAnchor.constraint(equalTo: view.leadingAnchor),
button.bottomAnchor.constraint(equalTo: view.bottomAnchor),
button.trailingAnchor.constraint(equalTo: view.trailingAnchor),
button.heightAnchor.constraint(equalToConstant: 50)
])
}
#objc
private func didTapAddView()
{
let customView = UIView()
customView.backgroundColor = .white
customView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(customView)
view.addConstraints([
customView.leadingAnchor.constraint(equalTo: view.leadingAnchor,
constant: 16),
customView.topAnchor.constraint(equalTo: view.topAnchor,
constant: 16),
customView.trailingAnchor.constraint(equalTo: view.trailingAnchor,
constant: -16),
customView.bottomAnchor.constraint(equalTo: button.topAnchor,
constant: -16)
])
}
}
Then I created your container view controller with the scroll view and embedded the child vc into the view controller:
class ScrollTestViewController: UIViewController
{
private let scrollView = UIScrollView()
private let childVC1 = ChildVC()
private let childVC2 = ChildVC()
private let childVCHeight: CGFloat = 250
private let childVCWidth: CGFloat = UIScreen.main.bounds.width
override func viewDidLoad()
{
super.viewDidLoad()
view.backgroundColor = .white
title = "Scroll Test"
configureScrollView()
configureChildVC1()
configureChildVC2()
}
override func viewDidLayoutSubviews()
{
super.viewDidLayoutSubviews()
scrollView.contentSize = CGSize(width: childVC1.view.bounds.width * 2,
height: scrollView.bounds.height)
}
private func configureScrollView()
{
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
view.addConstraints([
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
private func configureChildVC1()
{
addChild(childVC1)
childVC1.view.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(childVC1.view)
view.addConstraints([
childVC1.view.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
childVC1.view.centerYAnchor.constraint(equalTo: scrollView.centerYAnchor),
childVC1.view.widthAnchor.constraint(equalToConstant: childVCWidth),
childVC1.view.heightAnchor.constraint(equalToConstant: childVCHeight)
])
}
private func configureChildVC2()
{
addChild(childVC2)
childVC2.view.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(childVC2.view)
view.addConstraints([
childVC2.view.leadingAnchor.constraint(equalTo: childVC1.view.trailingAnchor),
childVC2.view.centerYAnchor.constraint(equalTo: scrollView.centerYAnchor),
childVC2.view.widthAnchor.constraint(equalToConstant: childVCWidth),
childVC2.view.heightAnchor.constraint(equalToConstant: childVCHeight)
])
}
}
After doing this, you will get this result:
No different, user can scroll anywhere even when swiping on top of the newly added view.
So I made these changes:
Create a custom view subclass so I can recognize which view I am dragging over
class CustomView: UIView
{
}
Create a custom scrollview to disable interaction over specific views
fileprivate class CustomScrollView: UIScrollView
{
override func touchesShouldCancel(in view: UIView) -> Bool
{
// Just for demo, I added this
if view is CustomView
{
print("Scroll disabled, tapping custom view")
}
else
{
print("Scroll enabled")
}
// You only need this line
return !(view is CustomView)
}
}
Make the changes in the container view controller with the scroll view
// Replace private let scrollView = UIScrollView() with
private let scrollView = CustomScrollView()
// Add this as well
scrollView.delaysContentTouches = false
Make changes in the child view controllers to use Custom view when tapping the button
#objc
private func didTapAddView()
{
let customView = CustomView()
customView.backgroundColor = .white
customView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(customView)
view.addConstraints([
customView.leadingAnchor.constraint(equalTo: view.leadingAnchor,
constant: 16),
customView.topAnchor.constraint(equalTo: view.topAnchor,
constant: 16),
customView.trailingAnchor.constraint(equalTo: view.trailingAnchor,
constant: -16),
customView.bottomAnchor.constraint(equalTo: button.topAnchor,
constant: -16)
])
}
Now when you swipe over the view, it will prevent you from scrolling
Update based on Mihai's (OP's) comments
Do you have any idea how I could do it for a UIViewController instead
of UIView, Im asking because the view is currently UIViewController
and I lose some specifications about it in transforming it to an
UIView.
So on the button press the view will add a UIViewController instead of
a UIView
A scrollview can add UIViews to it's view hierarchy therefore you can only check if the view you are scrolling on is a specific type of view.
However, I still think the solution can work if you want to add a view controller on a button tap instead of a UIView.
Keep the custom view as it is:
fileprivate class CustomView: UIView
{
}
Create a view controller subclass and change the default view to be the custom view subclass
fileprivate class PurpleVC: UIViewController
{
override func loadView()
{
super.loadView()
// Change the default view from a UIView
// to be of type CustomView
view = CustomView()
view.backgroundColor = .purple
}
}
Add the new view controller on button tap instead of UIView
#objc
private func didTapAddView()
{
let customVC = PurpleVC()
customVC.view.translatesAutoresizingMaskIntoConstraints = false
addChild(customVC)
view.addSubview(customVC.view)
view.addConstraints([
customVC.view.leadingAnchor.constraint(equalTo: view.leadingAnchor,
constant: 16),
customVC.view.topAnchor.constraint(equalTo: view.topAnchor,
constant: 16),
customVC.view.trailingAnchor.constraint(equalTo: view.trailingAnchor,
constant: -16),
customVC.view.bottomAnchor.constraint(equalTo: button.topAnchor,
constant: -16)
])
}
No change to custom scroll view as it should still detect the custom view which is the main view inside your view controller
fileprivate class CustomScrollView: UIScrollView
{
override func touchesShouldCancel(in view: UIView) -> Bool
{
// Just for demo, I added this
if view is CustomView
{
print("Scroll disabled, tapping custom view")
}
else
{
print("Scroll enabled")
}
// You only need this line
return !(view is CustomView)
}
}

Is there a way to update views in StackView without removing the view and re adding it?

I have views which use autolayout. I know the exact width I want each view to be (each width is different). The StackView is nested inside of a collection view. The views inside the stack view are loaded dynamically from the main view controller. I want to update the stack views views when the collection view reloads without removing the views and adding them again. I cannot remove the views and re add them because some of the views have textfields which will dismiss the keyboard if reloaded. I have explained the code below
Thank you for any help.
EDIT
This is the layout I am looking for.
I use Carbon for rendering the views into the collection view:
private func render() {
renderer.render {
Section(
id: "testing row collection",
cells: {
Row(id: "row id", data: [
Input(
id: 6,
props: InputContent.State(
text: self.state.inputText,
placeholder: "Search",
size: .medium
),
onChange: { [weak self] text in
print("text is:", text)
self?.state.inputText = text
}
)
])
}
)
}
}
NOTE: the image and code do not match implementation. The image shows 3 views, the code only shows 1.
The class Row is the class that renders the view that holds the UIStackView. Inside that I have a list of views, at the moment only 1 view. It's sets text to be self.state.inputText which is a variable in the view controller. Then on any change in the textfield I set self.state.inputText to be that text. When the variable state is set, render() is run.
The Row class:
This class renders the actual UIView which is called RowContent. It calls the updateState(state:) method shown in the RowContent class. This is called when the collection view renders
The RowContent class:
class RowContent: UIView {
var stack: UIStackView
var state: State
struct State {
var views: [UIView] = [UIView]()
}
public func updateState(_ state: State? = nil) {
self.state = state ?? self.state
//updateView()
}
required init(state: State) {
self.state = state
self.stack = UIStackView(arrangedSubviews: state.views)
super.init(frame: .zero)
self.setupStackView()
}
...
}
The stack view gets populated in the initialiser with the views, then I add the constraints in setupStackview()
At the moment, the views never update when the collection view re renders, meaning that the text property in Input never gets updated. I want to update the views when the collection view re renders. This would be in the updateView() method which is commented out. I do not know how to update the views in the collectionView without removing the views and re adding them.
Thanks.
I have added an example here: https://github.com/4ndrewHarri5/ExampleRow
Give this a try...
We start with a Tag "base" view class - it will set the background color and rounded corners for the Tag views:
// background and rounded corners
class TagBaseView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
layer.cornerRadius = 12
layer.masksToBounds = true
backgroundColor = UIColor(red: 0.96, green: 0.95, blue: 0.97, alpha: 1.0)
}
}
Subclass TagBaseView, adding a UILabel:
class TagLabelView: TagBaseView {
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
override func commonInit() -> Void {
super.commonInit()
label.font = .boldSystemFont(ofSize: 18.0)
label.numberOfLines = 0
addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: topAnchor, constant: 8.0),
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0),
label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0),
label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8.0),
])
}
}
Subclass TagBaseView, adding a UITextField:
class TagFieldView: TagBaseView {
let field = UITextField()
var textChangeCallback: ((String)->())?
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
override func commonInit() -> Void {
super.commonInit()
field.font = .boldSystemFont(ofSize: 18.0)
addSubview(field)
field.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
// constrain text field Leading / Trailing
field.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0),
field.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0),
// center it vertically
field.centerYAnchor.constraint(equalTo: centerYAnchor),
// require at least 8-pts Top and Bottom
field.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: 8.0),
field.bottomAnchor.constraint(lessThanOrEqualTo: bottomAnchor, constant: -8.0),
])
field.addTarget(self, action: #selector(self.textDidChange(_:)), for: .editingChanged)
}
#objc func textDidChange(_ textField: UITextField) -> Void {
guard let s = textField.text else {
return
}
// tell the controller the text changed
textChangeCallback?(s)
}
}
View controller class - creates a horizontal stack view, with a TagLabelView "left" view, a TagLabelView "center" view, and a TagFieldView "right" view.
When we edit the text field in the "right" view, it will use a closure to "call back" to the controller where we handle the text change and update the left and center views:
class EditStackViewController: UIViewController {
let stack: UIStackView = {
let v = UIStackView()
v.spacing = 8
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
let leftView = TagLabelView()
let centerView = TagLabelView()
let rightView = TagFieldView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(stack)
stack.addArrangedSubview(leftView)
stack.addArrangedSubview(centerView)
stack.addArrangedSubview(rightView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain stack view Top / Leading / Trailing
// (no Bottom or Height)
stack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
stack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 8.0),
stack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -8.0),
// make "center" view 45% of the width
centerView.widthAnchor.constraint(equalTo: stack.widthAnchor, multiplier: 0.45),
// make "right" view equal width to "left" view
rightView.widthAnchor.constraint(equalTo: leftView.widthAnchor),
])
rightView.field.placeholder = "Search"
// TagSearchView tells us when the field is being edited
rightView.textChangeCallback = { [weak self] str in
guard let self = self else {
return
}
self.leftView.label.text = str
self.centerView.label.text = str
}
}
}
Results:

How to arrange a view in architecture MVC? When coding through code

I am studying architecture MVC and I write the interface through code.
I am trying to link a VIEW and a CONTROLLER.
But it doesn't work. What's my mistake?
Controller:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
ViewExample.setupUI()
}
}
View:
import UIKit
class ViewExample: UIView {
static func setupUI() {
let view = UIView()
let labelTitle: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Hello, world!"
return label
}()
view.backgroundColor = .white
view.addSubview(labelTitle)
NSLayoutConstraint.activate([
labelTitle.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10),
labelTitle.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
labelTitle.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I understand why a static is needed. Why doesn't it work for me? I have not found any good example on github. Therefore, I have to turn to you
I don't see why you would use static, you want to set up the UI of a UIView's instance, thus no need to have a static class method.
In your ViewExample:
import UIKit
class ViewExample: UIView {
func setupUI() {
let labelTitle: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Hello, world!"
return label
}()
self.backgroundColor = .white
self.addSubview(labelTitle)
NSLayoutConstraint.activate([
labelTitle.topAnchor.constraint(equalTo: self.safeAreaLayoutGuide.topAnchor, constant: 10),
labelTitle.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10),
labelTitle.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -10),
])
}
override init(frame: CGRect){
super.init(frame: frame)
setupUI()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupUI()
}
}
In your ViewController
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let view = ViewExample(frame: (x: 0, y: 0, width: 200, height: 50)) //Change the frame according to where you want to position your view
self.addSubview(view)
}
}

After a sheet is presented in SwiftUI, the text color of interactive UI elements changes to systemBlue?

I have a sheet that is presented when a button is pressed:
struct Button: View {
#State isPresented = false
var body: some View {
Button(action: { self.isPresented.toggle() },
label: { Text("Text Label") }
).sheet(isPresented: $isPresented, content: {
//sheet contents in here
})
}
}
The class seen below is essentially the view in UIKit (I removed some of the code from the functions because it doesn't really have anything to do with the problem, but I kept the function names in there with descriptions so you can interpret what it's doing)
class CustomCalloutView: UIView, MGLCalloutView {
lazy var leftAccessoryView = UIView()
lazy var rightAccessoryView = UIView()
weak var delegate: MGLCalloutViewDelegate?
//MARK: Subviews -
let personImg: UIImageView = {
let img = UIImage(systemName: "person.fill")
var imgView = UIImageView(image: img)
//imgView.tintColor = UIColor(ciColor: .black)
imgView.translatesAutoresizingMaskIntoConstraints = false
return imgView
}()
let clockImg: UIImageView = {
let img = UIImage(systemName: "clock")
var imgView = UIImageView(image: img)
//imgView.tintColor = UIColor(ciColor: .black)
imgView.translatesAutoresizingMaskIntoConstraints = false
return imgView
}()
//Initialization of the view
required init() {
super.init(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: UIScreen.main.bounds.width * 0.75, height: 130)))
setup()
}
//other initializer
required init?(coder decoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//essentially just positioning the view
override var center: CGPoint {
set {
var newCenter = newValue
newCenter.y -= bounds.midY
super.center = newCenter
}
get {
return super.center
}
}
//setting it up
func setup() {
// setup this view's properties
self.backgroundColor = UIColor.clear
self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(CustomCalloutView.calloutTapped)))
// And the subviews
self.addSubview(personImg)
self.addSubview(clockImg)
// Add Constraints to subviews
//Positioning the clock image
clockImg.topAnchor.constraint(equalTo: self.separatorLine.bottomAnchor, constant: spacing).isActive = true
clockImg.leftAnchor.constraint(equalTo: self.leftAnchor, constant: spacing).isActive = true
clockImg.rightAnchor.constraint(equalTo: self.timeLabel.leftAnchor, constant: -spacing / 2).isActive = true
clockImg.heightAnchor.constraint(equalToConstant: 20.0).isActive = true
//Positioning the person image
personImg.topAnchor.constraint(equalTo: self.timeLabel.bottomAnchor, constant: spacing / 2).isActive = true
personImg.leftAnchor.constraint(equalTo: self.leftAnchor, constant: spacing).isActive = true
personImg.rightAnchor.constraint(equalTo: self.peopleLabel.leftAnchor, constant: -spacing / 2).isActive = true
personImg.heightAnchor.constraint(equalToConstant: 20.0).isActive = true
}
func presentCallout(from rect: CGRect, in view: UIView, constrainedTo constrainedRect: CGRect, animated: Bool)
//presenting the view
}
func dismissCallout(animated: Bool) {
//dismissing the view
}
#objc func calloutTapped() {
//respond to the view being tapped
}
}
When the sheet is presented and then dismissed, it causes other UI elements that are coded in UIKit (like text buttons, for example) to have their text turn color to the systemBlue UIColor...any idea how to fix this?
There is not enough code provided to test, but the reason might be in
struct Button: View { // << this custom view named as standard Button !!!
#State isPresented = false
it is named the same as standard SwiftUI component Button so this can confuse rendering engine.
Try to rename this (and others if you practice this) to something unique to your app, like MyButton or CustomButton, SheetButton, etc.

Change view with Segment View Control

I have created a view in my View controller which has UISegmentControl and a UIScrollView
let segmentControl : UISegmentedControl = {
let segmentItems = ["Personal","Statistics","Calendar"]
let segmentControl = UISegmentedControl(items: segmentItems)
segmentControl.selectedSegmentIndex = 0
segmentControl.addTarget(self, action: #selector(selectIn(sender:)), for: .valueChanged)
segmentControl.translatesAutoresizingMaskIntoConstraints = false
return segmentControl
}()
let subView : UIScrollView = {
let view = UIScrollView()
view.backgroundColor = .red
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
In viewDidLoad I added
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.isHidden = true
view.addSubview(segmentControl)
view.addSubview(subView)
setLayout()
}
and added layout as follows
func setLayout(){
NSLayoutConstraint.activate([
segmentControl.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10),
segmentControl.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20),
segmentControl.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20),
segmentControl.heightAnchor.constraint(equalToConstant: 30),
subView.topAnchor.constraint(equalTo: segmentControl.bottomAnchor, constant: 10),
subView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 20),
subView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -20),
subView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
])
}
and tried to add PersonalView (UIView) when any segmentControl is pressed
#objc func selectIn(sender: UISegmentedControl){
subView.addSubview(pvc)
}
My personalView is as follows
class PersonalView: UIView, UICollectionViewDelegate, UICollectionViewDataSource, UITableViewDelegate, UITableViewDataSource {
let tempValueForTable : Int = 10
let todayLabel : UILabel = {
let label = UILabel()
label.text = "Today"
label.font = .montserratSemiBold
label.textAlignment = .center
label.backgroundColor = .green
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(todayLabel)
setLayout()
}
private func setLayout(){
NSLayoutConstraint.activate([
todayLabel.topAnchor.constraint(equalTo: self.topAnchor),
todayLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 20),
todayLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -20),
todayLabel.heightAnchor.constraint(equalToConstant: 25),
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}}
Still I am not able to get view and in further update I need to add more view in same ScrollView
1.when you are using auto layout constraints you must set this false after add.
SomeView.translatesAutoresizingMaskIntoConstraints = false
2.After you add your subView you must set its constraints and call view.layoutIfNeeded()
subView.addSubview(pvc)
pvc.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
pvc.trailingAnchor.constraint(equalTo: subView.trailingAnchor),
pvc.leadingAnchor.constraint(equalTo: subView.leadingAnchor),
pvc.topAnchor.constraint(equalTo: subView.topAnchor),
pvc.bottomAnchor.constraint(equalTo: subView.bottomAnchor),
])
view.layoutIfNeeded()