如何从第一个视图控制器访问的类中推送第二个视图控制器?

时间:2019-08-08 13:39:15

标签: ios swift

我已经以编程方式初始化了第一个视图控制器以显示日历。我使用下面的gitHub文件中的代码显示日历: https://github.com/Akhilendra/calenderAppiOS

我对代码进行了一些更改,以删除更改颜色的功能,并将导航栏按钮“主题”替换为标有“历史记录”的按钮。 我还在Main.storyboard上创建了navigationController和ViewController。我还已经将ViewController storyBoard对象链接到ViewController类。 在链接的项目中,当您单击日期时,该特定单元格会更改颜色。但是在我的项目中,单击日期时,我希望将用户转到显示日期的下一个屏幕(在其他功能中,我想执行的操作)。

日历的didSelectItem()函数位于名为CalendarView的类中。这里的问题是,由于navigationController是UIViewController类的对象,因此无法访问此类中的navigationController.pushViewController()。

我尝试创建firstViewController类的实例,并在该实例上使用pushViewController,但这没有用。 该项目运行正常,并且显示了日历并选择了单元格。唯一的问题是不会出现下一个屏幕。

//视图控制器:

class ViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.

    //Title for the view:
    self.title = "My Calendar"
    //Month-year will be displayed if this property is set to false:
    self.navigationController?.navigationBar.isTranslucent=false
    //Bg colour of the entire view:
    self.view.backgroundColor=UIColor.white

    //Add the subview that contains the calendar:
    view.addSubview(calendarView)
    //Constraints for the calendar:
    calendarView.topAnchor.constraint(equalTo: view.topAnchor, constant: 10).isActive=true
    calendarView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -12).isActive=true
    calendarView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 12).isActive=true
    calendarView.heightAnchor.constraint(equalToConstant: 365).isActive=true

    //The left bar button on navigation controller:
    let leftBarBtn = UIBarButtonItem(title: "History", style: .plain, target: self, action: #selector(leftBarBtnAction))
    self.navigationItem.leftBarButtonItem = leftBarBtn
}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    calendarView.myCollectionView.collectionViewLayout.invalidateLayout()
}

//Defines what happens when left bar button is clicked:
@objc func leftBarBtnAction(sender: UIBarButtonItem) {

    print("History")

}

//Object of type CalendarView:

let calendarView: CalendarView = {
    let v=CalendarView()
    v.translatesAutoresizingMaskIntoConstraints=false
    return v
}() 

}

// CalendarView类:

class CalendarView: UIView, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, MonthViewDelegate {

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 changeTheme() {
    myCollectionView.reloadData()

    monthView.lblName.textColor = UIColor.blue
    //Colour of the button for the next month:
    monthView.btnRight.setTitleColor(UIColor.blue, for: .normal)
    //Colour of the button for the previous month:
    monthView.btnLeft.setTitleColor(UIColor.blue, for: .normal)

    for i in 0..<7 {
        (weekdaysView.myStackView.subviews[i] as! UILabel).textColor = UIColor.blue
    }
}

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 {
            //Disable user interaction on past dates
            cell.isUserInteractionEnabled=false
            //Colour of the text in past date cells
            cell.lbl.textColor = UIColor.lightGray
        } else {
            //Enable user interaction on upcoming dates
            cell.isUserInteractionEnabled=true
            //Colour of the text in upcoming date cells
            cell.lbl.textColor = UIColor.blue
        }
    }
    return cell
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let cell=collectionView.cellForItem(at: indexPath)
    //Print the selected date:
    let lbl = cell?.subviews[1] as! UILabel

    print(lbl.text!)


}



func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let width = collectionView.frame.width/7 - 8
    let height: CGFloat = 40
    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
}()

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
    return myCollectionView
}()

 required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
}

class dateCVCell: UICollectionViewCell {
override init(frame: CGRect) {
    super.init(frame: frame)
    backgroundColor=UIColor.clear
    layer.cornerRadius=5
    layer.masksToBounds=true

    setupViews()
}

func setupViews() {
    addSubview(lbl)
    lbl.topAnchor.constraint(equalTo: topAnchor).isActive=true
    lbl.leftAnchor.constraint(equalTo: leftAnchor).isActive=true
    lbl.rightAnchor.constraint(equalTo: rightAnchor).isActive=true
    lbl.bottomAnchor.constraint(equalTo: bottomAnchor).isActive=true
}

let lbl: UILabel = {
    let label = UILabel()
    label.text = "00"
    label.textAlignment = .center
    label.font=UIFont.systemFont(ofSize: 16)
    label.textColor=UIColor.darkGray
    label.translatesAutoresizingMaskIntoConstraints=false
    return label
}()

 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)
}
}

// MonthView类:

// The protocol with didChangeMonth function:
protocol MonthViewDelegate: class {
func didChangeMonth(monthIndex: Int, year: Int)
}

class MonthView: UIView {
//The array that contains the name of the months:
var monthsArr = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
 //Index of the current month:
 var currentMonthIndex = 0
 //Index of the current year:
 var currentYear: Int = 0

//Define an object of the protocol MonthViewDelegate:
var delegate: MonthViewDelegate?

override init(frame: CGRect) {
    super.init(frame: frame)
    self.backgroundColor=UIColor.clear

    //Index of the current month:
    currentMonthIndex = Calendar.current.component(.month, from: Date()) - 1
    //Index of the current year:
    currentYear = Calendar.current.component(.year, from: Date())

    setupViews()

    //Disable the previous month button on launch:
    btnLeft.isEnabled=false
}

//Change the number of days in a month(next/previous):
 @objc func btnLeftRightAction(sender: UIButton) {
    //When next month button is clicked:
    if sender == btnRight {
        //Increment the index of the current month:
        currentMonthIndex += 1
        //Check if next month is January of the next year:
        if currentMonthIndex > 11 {
            //Reset the current month index:
            currentMonthIndex = 0
            //Increment the current year:
            currentYear += 1
        }
    }
        //When previous month button is clicked:
    else {
        //Decrement the index of the current month:
        currentMonthIndex -= 1
        //Check if previous month is December of the last year:
        if currentMonthIndex < 0 {
            //Reset the current month index:
            currentMonthIndex = 11
            //Decrement the current year:
            currentYear -= 1
        }
    }
    // Set label text for Month-Year:
    lblName.text="\(monthsArr[currentMonthIndex]) \(currentYear)"
    //Call didChangeMonth on delegate object:
    delegate?.didChangeMonth(monthIndex: currentMonthIndex, year: currentYear)
}

func setupViews() {
    //Add label 'Month-Year'
    self.addSubview(lblName)
    //Constraints for label Month-Year:
    lblName.topAnchor.constraint(equalTo: topAnchor).isActive=true
    lblName.centerXAnchor.constraint(equalTo: centerXAnchor).isActive=true
    lblName.widthAnchor.constraint(equalToConstant: 150).isActive=true
    lblName.heightAnchor.constraint(equalTo: heightAnchor).isActive=true

    //Set label text for Month-Year:
    lblName.text="\(monthsArr[currentMonthIndex]) \(currentYear)"

    //Add view for 'next month' button:
    self.addSubview(btnRight)
    //Constraints for 'next month' button:
    btnRight.topAnchor.constraint(equalTo: topAnchor).isActive=true
    btnRight.rightAnchor.constraint(equalTo: rightAnchor).isActive=true
    btnRight.widthAnchor.constraint(equalToConstant: 50).isActive=true
    btnRight.heightAnchor.constraint(equalTo: heightAnchor).isActive=true

    //Add view for 'previous month' button:
    self.addSubview(btnLeft)
    btnLeft.topAnchor.constraint(equalTo: topAnchor).isActive=true
    btnLeft.leftAnchor.constraint(equalTo: leftAnchor).isActive=true
    btnLeft.widthAnchor.constraint(equalToConstant: 50).isActive=true
    btnLeft.heightAnchor.constraint(equalTo: heightAnchor).isActive=true
}

//The label that displays Month-year
let lblName: UILabel = {
    let lbl=UILabel()
    //Default text for month and year:
    lbl.text="Default Month Year text"
    //Colour of month and year:
    lbl.textColor = UIColor.blue
    //Alignment of month and year:
    lbl.textAlignment = .center
    //Font size and style of month and year:
    lbl.font=UIFont.boldSystemFont(ofSize: 16)
    lbl.translatesAutoresizingMaskIntoConstraints=false
    return lbl
}()

//Button for next month:
let btnRight: UIButton = {
    let btn=UIButton()
    //Title for next month button:
    btn.setTitle(">", for: .normal)
    //Title colour of next month button:
    btn.setTitleColor(UIColor.blue, for: .normal)
    btn.translatesAutoresizingMaskIntoConstraints=false
    //Function on next month button click:
    btn.addTarget(self, action: #selector(btnLeftRightAction(sender:)), for: .touchUpInside)
    return btn
}()

//Button for previous month:
let btnLeft: UIButton = {
    let btn=UIButton()
    //Title for previous month button:
    btn.setTitle("<", for: .normal)
    //Title colour for previous month button when enabled:
    btn.setTitleColor(UIColor.blue, for: .normal)
    btn.translatesAutoresizingMaskIntoConstraints=false
    //Function on previous month button click:
    btn.addTarget(self, action: #selector(btnLeftRightAction(sender:)), for: .touchUpInside)
    //Title colour of the previous button when disabled:
    btn.setTitleColor(UIColor.lightGray, for: .disabled)
    return btn
}()

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
}

// WeekdaysView类:

class WeekdaysView: UIView {

override init(frame: CGRect) {
    super.init(frame: frame)
    self.backgroundColor=UIColor.clear

    setupViews()
}

 func setupViews() {
    addSubview(myStackView)
    myStackView.topAnchor.constraint(equalTo: topAnchor).isActive=true
    myStackView.leftAnchor.constraint(equalTo: leftAnchor).isActive=true
    myStackView.rightAnchor.constraint(equalTo: rightAnchor).isActive=true
    myStackView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive=true

    //Array that contains name of the days in a week:
    var daysArr = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]
    //Iteration for the properties of each day in a week:
    for i in 0..<7 {
        let lbl=UILabel()
        //Text in the label for weekdays:
        lbl.text=daysArr[i]
        //Alignment of the text in week day label:
        lbl.textAlignment = .center
        //Colour of the label for weekdays:
        lbl.textColor = UIColor.blue
        //Stack that contains all labels with weekday names:
        myStackView.addArrangedSubview(lbl)
    }
}

//The stack that will contain the names of the days in a week:
let myStackView: UIStackView = {
    let stackView=UIStackView()
    //Distribute the labels as:
    stackView.distribution = .fillEqually
    stackView.translatesAutoresizingMaskIntoConstraints=false
    return stackView
}()

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
}

2 个答案:

答案 0 :(得分:0)

您可以定义委托协议。例如:HandleDateTransfer

  1. 使用该功能定义协议。例如setDate()

  2. CalendarView类添加一个弱的委托属性。

    弱var dateTransferdelegate:HandleDateTransfer?

  3. 将委托附加到CalendarView类。

  4. 符合协议,并在要设置日期的函数中实现setDate()方法。

  5. setDate()函数内调用didSelectItemAt方法。

答案 1 :(得分:0)

使用与didChangeMonth功能相同的委托/协议模式。

基本上,创建一个新协议:

// The protocol with didSelectDate function:
protocol SelectDateDelegate: class {
    func didSelectDate(dayIndex: Int, monthIndex: Int, year: Int)
}

让ViewController符合该协议

class ViewController: UIViewController, SelectDateDelegate {

    override func viewDidLoad() {
         // as normal ...

         view.addSubview(calendarView)

         // set the new delegate
         calendarView.delegate = self

    }

    func didSelectDate(dayIndex: Int, monthIndex: Int, year: Int) {
        let vc = DateDetailViewController()
        vc.dateData = dayIndex // or however you're managing the data
        self.navigationController?.pushViewController(vc, animated: true)
    }

}

然后在CalendarView类中:

var delegate: SelectDateDelegate?

didSelectItemAt中的

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let cell=collectionView.cellForItem(at: indexPath)
    //Print the selected date:
    let lbl = cell?.subviews[1] as! UILabel

    print(lbl.text!)

    // whatever variables / properties you're using to track day / month / year
    delegate?.didSelectDate(dayIndex: dayVal, monthIndex: monthVal, year: yearVal)

}