我的表单很长,创建了一个containerView(UIView),其中包含一个自定义Calendar和几个textField。 UIView嵌入在scrollView中,因此我可以滚动长格式。
ScrollView
-ContainerView // UIView
-CustomCalendar // contains a UICollectionView
-TextField
-TextField
//etc etc..
苹果说:
您不应在UIScrollView中嵌入UIWebView或UITableView对象 对象。如果这样做,可能会导致意外行为,因为触摸 这两个对象的事件可能会混合在一起并被错误地处理。
要解决这个问题,我尝试禁用CalendarView上的滚动,但没有任何区别:
// this is inside the CalenderView file
myCollectionView.isScrollEnabled = false
我从here和here那里获得了日历,它使用collectionView显示日期以及何时选择了didSelectItem触发日期。
问题是因为自定义日历包含collectionView,并且当我触摸日期didSelecetItem无法运行时,它位于scrollView内。
如何获取日历的collectionView来接收触摸事件?
当日历不在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)是collectionView。
答案 0 :(得分:1)
我找到了@Jaydeep的answer here,并从@zambrey获得了explanation。
这个想法是告诉手势识别器不要吞下触摸事件。为此,您需要将singleTap的cancelsTouchesInView属性设置为NO,默认情况下为YES。
您想告诉scrollView不要吃掉所有的触摸事件,您可以通过向其添加一个点击手势识别器并设置点击的
来做到这一点singleTap.cancelsTouchesInView = false
我在将CalenderView嵌入ScrollView内的UIView的文件中添加了tapGesture,而不是具有collectionView的文件。
override func viewDidLoad() {
super.viewDidLoad()
createAnchors()
// add these 4 lines
let singleTap = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
singleTap.cancelsTouchesInView = false
singleTap.numberOfTapsRequired = 1
scrollView.addGestureRecognizer(singleTap)
}
// add this target method. I didn't add any code whatsoever inside of it
func handleTap(_ recognizer: UITapGestureRecognizer) {
// I literally left this blank
}