У меня очень длинная форма и я создал containerView (UIView), который содержит пользовательский календарь и несколько текстовых полей.UIView встроен в scrollView, так что я могу прокрутить длинную форму.
ScrollView
-ContainerView // UIView
-CustomCalendar // contains a UICollectionView
-TextField
-TextField
//etc etc..
Apple говорит:
Вы не должны вставлять объекты UIWebView или UITableView в объекты UIScrollView.Если вы это сделаете, это может привести к неожиданному поведению, потому что события касания для двух объектов могут быть смешаны и неправильно обработаны.
Чтобы обойти это, я попытался отключить прокрутку в CalendarView, но это не удалосьне имеет значения:
// this is inside the CalenderView file
myCollectionView.isScrollEnabled = false
Я получил календарь из здесь и здесь , и он использует collectionView для отображения дат, и когда дата выбрана, didSelectItem isсработало.
Проблема в том, что пользовательский календарь содержит коллекцию ViewView, и он находится внутри scrollView, когда я касаюсь даты. didSelecetItem не запускается.
Как получить коллекцию календаря ViewViewполучать сенсорные события?
Календарь работает нормально, когда его нет внутри scrollView
let scrollView: UIScrollView = {
let sv = UIScrollView()
sv.translatesAutoresizingMaskIntoConstraints = false
sv.showsVerticalScrollIndicator = false
return sv
}()
let containerView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .white
return view
}()
let calendarView: CalendarView = {
let view = CalendarView() // contains a collectionView
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
createAnchors()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
scrollView.contentSize = CGSize(width: scrollView.contentSize.width, height: 1000)
}
func createAnchors() {
view.addSubview(scrollView)
scrollView.addSubview(containerView)
scrollView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
containerView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
containerView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
calendarView.topAnchor.constraint(equalTo: containerView.topAnchor, constant: verticalPadding).isActive = true
calendarView.leftAnchor.constraint(equalTo: containerView.leftAnchor, constant: 10).isActive = true
calendarView.rightAnchor.constraint(equalTo: containerView.rightAnchor, constant: -10).isActive = true
calendarView.heightAnchor.constraint(equalToConstant: 290).isActive = true
// textFields are added...
}
Вот файл для CalenderView.Есть еще 2 файла, которые я не включил, потому что это только представления, которые создают недели и месяцы.
class CalendarView: UIView, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, MonthViewDelegate {
let myCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
let myCollectionView=UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
myCollectionView.showsHorizontalScrollIndicator = false
myCollectionView.translatesAutoresizingMaskIntoConstraints=false
myCollectionView.backgroundColor=UIColor.clear
myCollectionView.allowsMultipleSelection=false
myCollectionView.isScrollEnabled = false
return myCollectionView
}()
var numOfDaysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31]
var currentMonthIndex: Int = 0
var currentYear: Int = 0
var presentMonthIndex = 0
var presentYear = 0
var todaysDate = 0
var firstWeekDayOfMonth = 0 //(Sunday-Saturday 1-7)
override init(frame: CGRect) {
super.init(frame: frame)
initializeView()
}
func initializeView() {
currentMonthIndex = Calendar.current.component(.month, from: Date())
currentYear = Calendar.current.component(.year, from: Date())
todaysDate = Calendar.current.component(.day, from: Date())
firstWeekDayOfMonth=getFirstWeekDay()
//for leap years, make february month of 29 days
if currentMonthIndex == 2 && currentYear % 4 == 0 {
numOfDaysInMonth[currentMonthIndex-1] = 29
}
//end
presentMonthIndex=currentMonthIndex
presentYear=currentYear
setupViews()
myCollectionView.delegate=self
myCollectionView.dataSource=self
myCollectionView.register(dateCVCell.self, forCellWithReuseIdentifier: "Cell")
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return numOfDaysInMonth[currentMonthIndex-1] + firstWeekDayOfMonth - 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell=collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! dateCVCell
cell.backgroundColor=UIColor.clear
if indexPath.item <= firstWeekDayOfMonth - 2 {
cell.isHidden=true
} else {
let calcDate = indexPath.row-firstWeekDayOfMonth+2
cell.isHidden=false
cell.lbl.text="\(calcDate)"
if calcDate < todaysDate && currentYear == presentYear && currentMonthIndex == presentMonthIndex {
cell.isUserInteractionEnabled=false
cell.lbl.textColor = UIColor.lightGray
} else {
cell.isUserInteractionEnabled=true
cell.lbl.textColor = Style.activeCellLblColor
}
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell=collectionView.cellForItem(at: indexPath)
cell?.backgroundColor=Colors.darkRed
let lbl = cell?.subviews[1] as! UILabel
lbl.textColor=UIColor.white
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell=collectionView.cellForItem(at: indexPath)
cell?.backgroundColor=UIColor.clear
let lbl = cell?.subviews[1] as! UILabel
lbl.textColor = Style.activeCellLblColor
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.frame.width/7 - 8
let height: CGFloat = 30
return CGSize(width: width, height: height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 8.0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 8.0
}
func getFirstWeekDay() -> Int {
let day = ("\(currentYear)-\(currentMonthIndex)-01".date?.firstDayOfTheMonth.weekday)!
//return day == 7 ? 1 : day
return day
}
func didChangeMonth(monthIndex: Int, year: Int) {
currentMonthIndex=monthIndex+1
currentYear = year
//for leap year, make february month of 29 days
if monthIndex == 1 {
if currentYear % 4 == 0 {
numOfDaysInMonth[monthIndex] = 29
} else {
numOfDaysInMonth[monthIndex] = 28
}
}
//end
firstWeekDayOfMonth=getFirstWeekDay()
myCollectionView.reloadData()
monthView.btnLeft.isEnabled = !(currentMonthIndex == presentMonthIndex && currentYear == presentYear)
}
func setupViews() {
addSubview(monthView)
monthView.topAnchor.constraint(equalTo: topAnchor).isActive=true
monthView.leftAnchor.constraint(equalTo: leftAnchor).isActive=true
monthView.rightAnchor.constraint(equalTo: rightAnchor).isActive=true
monthView.heightAnchor.constraint(equalToConstant: 35).isActive=true
monthView.delegate=self
addSubview(weekdaysView)
weekdaysView.topAnchor.constraint(equalTo: monthView.bottomAnchor).isActive=true
weekdaysView.leftAnchor.constraint(equalTo: leftAnchor).isActive=true
weekdaysView.rightAnchor.constraint(equalTo: rightAnchor).isActive=true
weekdaysView.heightAnchor.constraint(equalToConstant: 30).isActive=true
addSubview(myCollectionView)
myCollectionView.topAnchor.constraint(equalTo: weekdaysView.bottomAnchor, constant: 0).isActive=true
myCollectionView.leftAnchor.constraint(equalTo: leftAnchor, constant: 0).isActive=true
myCollectionView.rightAnchor.constraint(equalTo: rightAnchor, constant: 0).isActive=true
myCollectionView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive=true
}
let monthView: MonthView = {
let v=MonthView()
v.translatesAutoresizingMaskIntoConstraints=false
return v
}()
let weekdaysView: WeekdaysView = {
let v=WeekdaysView()
v.translatesAutoresizingMaskIntoConstraints=false
return v
}()
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//get first day of the month
extension Date {
var weekday: Int {
return Calendar.current.component(.weekday, from: self)
}
var firstDayOfTheMonth: Date {
return Calendar.current.date(from: Calendar.current.dateComponents([.year,.month], from: self))!
}
}
//get date from string
extension String {
static var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter
}()
var date: Date? {
return String.dateFormatter.date(from: self)
}
}
Только для визуального представления CalendarView.Даты (1-30) являются коллекцией.