In my application, I created a scrollView and set the width of this scrollView to twice the width of the screen. Then I created two contentViews. (contentView1 and contentView2) I use these contentViews as two screens. When I click on the "YENİ KAYIT" button in contentView1, the scrollView moves forward and contentView2 comes. The problem with contentView2 is that if I click anywhere other than the Stop button, it goes to an irrelevant place.
You can click here for detailed video : https://github.com/krmdmr7/ProgrammaticScrollView/assets/120031527/a873700b-9bd9-466c-b9b4-8670a1e8604a
You can click here for detailed code : https://github.com/krmdmr7/ProgrammaticScrollView
My UI Views :
private var allRecordsScrollView: UIScrollView = {
let allRecordsScrollView = UIScrollView()
allRecordsScrollView.isPagingEnabled = true
allRecordsScrollView.contentInsetAdjustmentBehavior = .never
allRecordsScrollView.showsHorizontalScrollIndicator = false
allRecordsScrollView.translatesAutoresizingMaskIntoConstraints = false
allRecordsScrollView.contentSize = CGSize(width: UIScreen.main.bounds.width * 2, height: UIScreen.main.bounds.height)
return allRecordsScrollView
}()
private var contentView1: UIView = {
let contentView1 = UIView()
contentView1.translatesAutoresizingMaskIntoConstraints = false
contentView1.backgroundColor = UIColor(named: "LightGreen")
return contentView1
}()
private var contentView2: UIView = {
let contentView2 = UIView()
contentView2.translatesAutoresizingMaskIntoConstraints = false
contentView2.backgroundColor = UIColor(named: "Green")
contentView2.isHidden = true
return contentView2
}()
Life Cycle :
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
configureUI()
}
UI Görünümleri Kısıtlamaları :
private func configureUI(){
view.addSubview(allRecordsScrollView)
NSLayoutConstraint.activate([
allRecordsScrollView.topAnchor.constraint(equalTo: view.topAnchor),
allRecordsScrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
allRecordsScrollView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 2),
allRecordsScrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
// ContentViews constraints for allRecordsScrollView
allRecordsScrollView.addSubview(contentView1)
allRecordsScrollView.addSubview(contentView2)
NSLayoutConstraint.activate([
// contentView1 constraints for scrollView
contentView1.topAnchor.constraint(equalTo: allRecordsScrollView.topAnchor),
contentView1.bottomAnchor.constraint(equalTo: allRecordsScrollView.bottomAnchor),
contentView1.leadingAnchor.constraint(equalTo: allRecordsScrollView.leadingAnchor, constant: 0),
contentView1.widthAnchor.constraint(equalTo: allRecordsScrollView.widthAnchor, multiplier: 0.5),
contentView1.heightAnchor.constraint(equalTo: allRecordsScrollView.heightAnchor),
// contentView2 constraints for scrollView
contentView2.topAnchor.constraint(equalTo: allRecordsScrollView.topAnchor),
contentView2.bottomAnchor.constraint(equalTo: allRecordsScrollView.bottomAnchor),
contentView2.leadingAnchor.constraint(equalTo: contentView1.trailingAnchor),
contentView2.widthAnchor.constraint(equalTo: allRecordsScrollView.widthAnchor, multiplier: 0.5),
contentView2.heightAnchor.constraint(equalTo: allRecordsScrollView.heightAnchor)
])
}
Button Functions :
@objc func recordButtonTapped() {
print("Record button tapped.")
contentView2.isHidden = false
contentView1.isHidden = true
let xOffset = allRecordsScrollView.frame.width / 2
allRecordsScrollView.setContentOffset(CGPoint(x: xOffset, y: 0), animated: false)
}
@objc func stopRecordButtonTapped(){
contentView2.isHidden = true
contentView1.isHidden = false
print("Stop record button tapped.")
allRecordsScrollView.setContentOffset(CGPoint(x: 0, y: 0), animated: false)
}
You are making things very overcomplicated by using a UIScrollView
... and you're using it incorrectly anyway.
A much easier approach is to:
.clear
for both contentView1 and contentView2... that will allow the "bubble" image to "show through"Here is a modified version of your complete ViewController
class from your posted GitHub project:
class ViewController: UIViewController {
// MARK : UI Elements
private var contentView1: UIView = {
let contentView1 = UIView()
contentView1.translatesAutoresizingMaskIntoConstraints = false
// clear
//contentView1.backgroundColor = UIColor(named: "LightGreen")
contentView1.backgroundColor = .clear
return contentView1
}()
private var contentView2: UIView = {
let contentView2 = UIView()
contentView2.translatesAutoresizingMaskIntoConstraints = false
// clear
//contentView2.backgroundColor = UIColor(named: "Green")
contentView2.backgroundColor = .clear
return contentView2
}()
private let kendinYapLabel:UILabel = {
let kendinYapLabel = UILabel()
kendinYapLabel.translatesAutoresizingMaskIntoConstraints = false
kendinYapLabel.font = UIFont(name: "Overpass-Bold", size: 24.0)
kendinYapLabel.text = "KENDİN YAP"
kendinYapLabel.textColor = .white
return kendinYapLabel
}()
lazy var backButton: UIButton = {
let backButton = UIButton()
backButton.translatesAutoresizingMaskIntoConstraints = false
backButton.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside)
backButton.setImage(UIImage(named: "backIcon"), for: .normal)
backButton.setTitleColor(UIColor.white, for: .normal)
return backButton
}()
private let bigGreenTopBubbleImageView: UIImageView = {
let bigGreenTopBubbleImageView = UIImageView()
let image = UIImage(named: "bigGreenTopBubble")
bigGreenTopBubbleImageView.translatesAutoresizingMaskIntoConstraints = false
bigGreenTopBubbleImageView.image = image
bigGreenTopBubbleImageView.contentMode = .scaleAspectFill
return bigGreenTopBubbleImageView
}()
lazy var recordButton:UIButton = {
let recordButton = UIButton()
let image = UIImage(named: "recordButtonBGAll")
recordButton.translatesAutoresizingMaskIntoConstraints = false
recordButton.addTarget(self, action: #selector(recordButtonTapped), for: .touchUpInside)
recordButton.setImage(image, for: .normal)
return recordButton
}()
private let recorderVoicesLabel:UILabel = {
let recorderVoicesLabel = UILabel()
recorderVoicesLabel.translatesAutoresizingMaskIntoConstraints = false
recorderVoicesLabel.text = "KAYITLI SESLER"
recorderVoicesLabel.font = UIFont(name: "Overpass-Bold", size: 20.0)
recorderVoicesLabel.textColor = .white
return recorderVoicesLabel
}()
public var recordCounterLabel:UILabel = {
let recordCounterLabel = UILabel()
recordCounterLabel.translatesAutoresizingMaskIntoConstraints = false
recordCounterLabel.font = UIFont(name: "Overpass-Regular", size: 100.0)
recordCounterLabel.text = "00:00"
recordCounterLabel.textColor = .white
return recordCounterLabel
}()
public var recordingStatusLabel:UILabel = {
let recordingStatusLabel = UILabel()
recordingStatusLabel.translatesAutoresizingMaskIntoConstraints = false
recordingStatusLabel.font = UIFont(name: "Overpass-Regular", size: 20.0)
recordingStatusLabel.text = "Ses kaydı bekleniyor."
recordingStatusLabel.textColor = .white
return recordingStatusLabel
}()
lazy var stopRecordButton:UIButton = {
let stopRecordButton = UIButton()
let image = UIImage(named: "recordButtonStopIcon")
stopRecordButton.translatesAutoresizingMaskIntoConstraints = false
stopRecordButton.addTarget(self, action: #selector(stopRecordButtonTapped), for: .touchUpInside)
stopRecordButton.setImage(image, for: .normal)
return stopRecordButton
}()
// MARK : Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
// set view background color
view.backgroundColor = UIColor(named: "LightGreen")
configure()
}
private func configure(){
configureUI()
}
// MARK : Setup UI
private func configureUI(){
// add bigGreenTopBubbleImageView as the first subview
// the "content" views will have clear backgrounds,
// so we see the "bubble" image through them
view.addSubview(bigGreenTopBubbleImageView)
NSLayoutConstraint.activate([
// BigGreenBubble constraints
bigGreenTopBubbleImageView.topAnchor.constraint(equalTo: view.topAnchor, constant: -70),
bigGreenTopBubbleImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0),
bigGreenTopBubbleImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0),
bigGreenTopBubbleImageView.heightAnchor.constraint(equalToConstant: 466),
])
// add the two "content" views
view.addSubview(contentView1)
view.addSubview(contentView2)
NSLayoutConstraint.activate([
// constrain both "content" views to fill the view
// contentView2 will be "overlaid on top of" contentView1
contentView1.topAnchor.constraint(equalTo: view.topAnchor),
contentView1.leadingAnchor.constraint(equalTo: view.leadingAnchor),
contentView1.trailingAnchor.constraint(equalTo: view.trailingAnchor),
contentView1.bottomAnchor.constraint(equalTo: view.bottomAnchor),
contentView2.topAnchor.constraint(equalTo: view.topAnchor),
contentView2.leadingAnchor.constraint(equalTo: view.leadingAnchor),
contentView2.trailingAnchor.constraint(equalTo: view.trailingAnchor),
contentView2.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
// add contentView1's subviews
contentView1.addSubview(backButton)
contentView1.addSubview(kendinYapLabel)
contentView1.addSubview(recordButton)
contentView1.addSubview(recorderVoicesLabel)
NSLayoutConstraint.activate([
// constrain subviews to contentView1, NOT to view
// Back button constraints
backButton.topAnchor.constraint(equalTo: contentView1.topAnchor, constant: 48),
backButton.leadingAnchor.constraint(equalTo: contentView1.leadingAnchor, constant: 20),
backButton.widthAnchor.constraint(equalToConstant: 50),
backButton.heightAnchor.constraint(equalToConstant: 54),
// KendinYapLabel constraints
kendinYapLabel.centerXAnchor.constraint(equalTo: contentView1.centerXAnchor),
kendinYapLabel.centerYAnchor.constraint(equalTo: backButton.centerYAnchor),
// RecordButton constraints
recordButton.topAnchor.constraint(equalTo: kendinYapLabel.bottomAnchor, constant: 55),
recordButton.leadingAnchor.constraint(equalTo: contentView1.leadingAnchor, constant: 91),
recordButton.trailingAnchor.constraint(equalTo: contentView1.trailingAnchor, constant: -91),
recordButton.heightAnchor.constraint(equalToConstant: 77),
// RecorderVoicesLabel constraints
recorderVoicesLabel.topAnchor.constraint(equalTo: recordButton.bottomAnchor, constant: 20),
recorderVoicesLabel.leadingAnchor.constraint(equalTo: contentView1.leadingAnchor, constant: 43),
recorderVoicesLabel.heightAnchor.constraint(equalToConstant: 25.5)
])
// add contentView2's subviews
contentView2.addSubview(recordCounterLabel)
contentView2.addSubview(recordingStatusLabel)
contentView2.addSubview(stopRecordButton)
NSLayoutConstraint.activate([
// constrain subviews to contentView2, NOT to view
// Record counter label constraints
recordCounterLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 200),
recordCounterLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
// Recording status label constraints
recordingStatusLabel.topAnchor.constraint(equalTo: recordCounterLabel.bottomAnchor, constant: 10),
recordingStatusLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
// Stop record button constraints
stopRecordButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -132),
stopRecordButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
stopRecordButton.widthAnchor.constraint(equalToConstant: 118),
stopRecordButton.heightAnchor.constraint(equalToConstant: 118)
])
// start with contentView2 hidden
contentView2.isHidden = true
}
// MARK : Functions
// MARK : Actions
@objc func recordButtonTapped() {
print("Record button tapped.")
// hide contentView1, show contentView2
contentView1.isHidden = true
contentView2.isHidden = false
}
@objc func backButtonTapped() {
print("Back button tapped.")
}
@objc func stopRecordButtonTapped(){
print("Stop record button tapped.")
// show contentView1, hide contentView2
contentView1.isHidden = false
contentView2.isHidden = true
}
}