FS calendar 오작동 및 개선

10 답변 글타래를 보이고 있습니다
  • 글쓴이
    • 정재 이
      참가자
      • 글작성 : 4
      • 답글작성 : 11
      1,510 포인트

      아래와 같이 구현하였습니다. click된 순간 동작하는 함수해서 click된 날짜를 deselect하고 DB와 이벤트 목록데이터에 추가한 뒤, reload하여 색상을 변화시켰습니다.

      import UIKit
      import FSCalendar
      
      class CalendarViewController: UIViewController, FSCalendarDataSource, FSCalendarDelegate, FSCalendarDelegateAppearance {
      
          @IBOutlet weak var calendar: FSCalendar!
      
          @IBOutlet weak var SegmentedControl: UISegmentedControl!
      
          let DB = DataBaseAPI.init()
          let Quary = DataBaseQuery.init()
      
          fileprivate lazy var dateFormatter: DateFormatter = {
              let formatter = DateFormatter()
              formatter.dateFormat = "yyyy-MM-dd"
              return formatter
          }()
      
      
          var fillDefaultColorsArray : Array<Array<String>> = []
          var fillDefaultColorsDictionary = [String : Int ]()
      
      
          let SegmentedBarData = ["🟩휴가","🟥훈련","🟨외출","🟦파견", "⬜️삭제"]
          let SegmentedBarColor = [UIColor.green,UIColor.red,UIColor.yellow,UIColor.blue , UIColor.clear]
      
          override func viewDidLoad() {
      
              super.viewDidLoad()
      
              //네비게이션바 세팅
              self.navigationItem.hidesBackButton = true;
              self.navigationItem.leftBarButtonItem = nil;
              let navview = Variable_Functions.init()
              self.navigationItem.titleView = navview.navView
      
      
              //세그먼트바 세팅
              SegmentedControl.removeAllSegments()
              SegmentedBarData.map({ text in
                 SegmentedControl.insertSegment(withTitle: text, at: SegmentedControl.numberOfSegments, animated: false)
              })
              SegmentedControl.selectedSegmentIndex = 0
      
      
              //DB에서 불러오기
              fillDefaultColorsArray = DB.query(statement: Quary.SelectStar(Tablename: "Calendar"), ColumnNumber: 2)
              fillDefaultColorsArray.map({ each in
                  fillDefaultColorsDictionary.updateValue(Int(each[1])! , forKey: each[0])
              })
              print(fillDefaultColorsDictionary)
      
              //self.calendar.deselect(self.calendar.today!)
              self.calendar.dataSource = self
              self.calendar.delegate = self
              self.calendar.register(FSCalendarCell.self, forCellReuseIdentifier: "CELL")
              self.calendar.allowsMultipleSelection = true
              self.calendar.swipeToChooseGesture.isEnabled = true
              self.calendar.appearance.caseOptions = [.headerUsesUpperCase,.weekdayUsesSingleUpperCase]
              self.calendar.appearance.borderRadius = 0
              self.calendar.appearance.borderRadius = 0
      
          }
      
      
          //날짜가 선택되어있을때
          func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
              let date_string = self.dateFormatter.string(from: date)
              //삭제
              if self.SegmentedControl.selectedSegmentIndex == 4 && fillDefaultColorsDictionary[date_string] != nil {
                  if (DB.delete(statement: Quary.Delete(Tablename: "Calendar", Condition: "marked_date = " + "'\(date_string)'"))){
                      print("delete success at calander")
                  }
              }else{
                  //기존 존재한다면 삭제하고 삽입한다.
                  if (DB.delete(statement: Quary.Delete(Tablename: "Calendar", Condition: "marked_date = " + "'\(date_string)'"))){
                      print("delete success at calander before insert")
                  }
                  if (DB.insert(statement: Quary.insert(Tablename: "Calendar", Values: " '\(date_string)', \(SegmentedControl.selectedSegmentIndex + 1)" ))){
                      print("insert success at calander")
                  }
              }
              fillDefaultColorsDictionary.updateValue(SegmentedControl.selectedSegmentIndex + 1 , forKey: date_string)
              //print(fillDefaultColorsDictionary)
              calendar.deselect(date)
              calendar.reloadData()
          }
      
          //기본색상
          func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, fillDefaultColorFor date: Date) -> UIColor? {
              //print("언제실행되는가?")
              let key = self.dateFormatter.string(from: date)
              if let colorindex = fillDefaultColorsDictionary[key] {
                  return SegmentedBarColor[colorindex-1]
              }else{
                  return  UIColor.clear
              }
          }
      
          func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, borderDefaultColorFor date: Date) -> UIColor? {
      
      
              let key = self.dateFormatter.string(from: date)
              if let colorindex = fillDefaultColorsDictionary[key] {
                 return SegmentedBarColor[colorindex-1]
             }else{
                 return  UIColor.clear
             }
          }
      
          func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, titleDefaultColorFor date: Date) -> UIColor? {
              return UIColor.black
          }
      
      
      }
      
      

      그러나 현재 문제점, 개선해야 할 점이 각각 1개 씩 있는데,
      문제점 1. – click을 하였을때, 클릭한 날짜가 아닌 다른 cell이 클릭되는 듯한 애니메이션이 발생합니다. 영상은 동영상을 참고하십시오. 왜 이런 문제가 발생할까요?

      개선해야 할점 1. 저희는 이런 화면을 원하고 있는데, 색상이야 나중에 이쁜 색 수정하면 되겠지만, cell의 색상을 변경하여도 주변 cell과 이어지지 않습니다. 어떤 속성을 조절해야 할까요?
      목표 – https://drive.google.com/file/d/1RQnFbUDSvmm5olhQTL7MDuHYJpr95gnY/view?usp=sharing

      현재 – https://drive.google.com/file/d/1U8n7E88Fba4maISMv0De3yqD6dl0q02t/view?usp=sharing

      • 이 게시글은 정재 이에 의해 1 year, 6 months 전에 수정됐습니다.
    • 야곰
      키 마스터
      • 글작성 : 37
      • 답글작성 : 539
      18,860 포인트

      여러가지 문제 중에 제일 눈에 띄는 문제를 말씀드리면,

      날짜는 Date <-> String 변환을 계속 하면서 관리하는 것보다 Date대로 관리하는 것이 훨씬 좋습니다. DateString으로 관리하려고 하지 않는 것이 좋습니다. 화면에 보여주기 직전에만 String으로 변환해서 보여주도록 해보세요.

      개선점은 캘린더 라이브러리 배포자에게 질문해야 할 것 같습니다. 혹은 라이브러리에서 제공하는 공식문서나 사용법 등을 참고해야 할 것 같아요. 저는 해당 라이브러리를 사용해보지 않아서 모르겠습니다.
      만약 배포자가 해당 기능을 제공하는 것이 아니라면 직접 구현해야 할 것 같습니다.

      • 정재 이
        참가자
        • 글작성 : 4
        • 답글작성 : 11
        1,510 포인트

        해당 github에 문의를 좀 해봐야 할것같네요… self.calendar.dequeueReusableCell(withIdentifier: <#T##String#>, for: <#T##Date#>, at: <#T##FSCalendarMonthPosition#>) 이런게 적용되어 cell을 재사용하고 있어서 저런 현상이 나타나는것같은데 잘은 모르겠습니다ㅠ

    • 김수호 김
      참가자
      • 글작성 : 0
      • 답글작성 : 5
      1,460 포인트

      목표 링크처럼 하시고 싶으신거라면 cell 의 backgroundColor를 변경해주시면 될거같아요~

      그리고 제생각에는 다른 셀이 클릭되는것과 같은 현상이 일어나는건 didselect 에서  reloadData() 때문인거 같은데 …

      혹시나 reloadData() 주석처리 해보시고 테스트 해보세요 다른셀이 눌리는 것과 현상이 일어나는지

      • 이 답변은 김수호 김에 의해 1 year, 6 months 전에 수정됐습니다.
    • 정재 이
      참가자
      • 글작성 : 4
      • 답글작성 : 11
      1,510 포인트

      제가 가진 날짜 데이터를 바탕으로 해당 날짜 cell의 backgroundColor을 어떻게 바꿔줄 수 있을까요? 구글링을 해보았지만 전부 예전 코드라서 참고할만한게 없네요.

       let cell = self.calendar.cell(for: Date, at: MonthPosition)
      
      

      이라는 함수가 있긴한데, current Month Position을 return해주는 함수는 cell을 인자로 요구하네요… cell을 구하려면 Month를 알아야하고 Month를 구할려면 cell을 알아야한다니…

      let celss = self.calendar.visibleCells() 
      

      로 현재 보이는 Cell들의 배열을 참조할 수는 있는데, Cell의 멤버변수나 함수에 해당 Cell의 date를 return 하는 녀석이 보이지 않습니다…

    • 정재 이
      참가자
      • 글작성 : 4
      • 답글작성 : 11
      1,510 포인트

      제가 가진 날짜 데이터를 바탕으로 해당 날짜 cell의 backgroundColor을 어떻게 바꿔줄 수 있을까요? 구글링을 해보았지만 전부 예전 코드라서 참고할만한게 없네요.

       let cell = self.calendar.cell(for: Date, at: MonthPosition)
      
      

      이라는 함수가 있긴한데, current Month Position을 return해주는 함수는 cell을 인자로 요구하네요… cell을 구하려면 Month를 알아야하고 Month를 구할려면 cell을 알아야한다니…

      let celss = self.calendar.visibleCells() 
      

      로 현재 보이는 Cell들의 배열을 참조할 수는 있는데, Cell의 멤버변수나 함수에 해당 Cell의 date를 return 하는 녀석이 보이지 않습니다…

    • 김수호 김
      참가자
      • 글작성 : 0
      • 답글작성 : 5
      1,460 포인트

      Date 값을 통해 Month 값 가져올 수 있을텐데요?

       

      저도 할거 없는 중에 좀 알아봤는데요

      FSCalendar의 MonthPostion이 저희가 알던 month 값이 아닌거 같네요 ? 

      달력에 26…30 1…30 1…5

      이렇게 있다면 26 … 30 의 MonthPostion은 0 , 1…30  은 1 , 1…5  은 2 가 되네요 참고 하세요~

       

      typedef NS_ENUM(NSUInteger, FSCalendarMonthPosition) {
          FSCalendarMonthPositionPrevious,
          FSCalendarMonthPositionCurrent,
          FSCalendarMonthPositionNext,
      
          FSCalendarMonthPositionNotFound = NSNotFound
      };
      
      • 이 답변은 김수호 김에 의해 1 year, 6 months 전에 수정됐습니다.
      • 이 답변은 김수호 김에 의해 1 year, 6 months 전에 수정됐습니다.
    • 정재 이
      참가자
      • 글작성 : 4
      • 답글작성 : 11
      1,510 포인트

      여러분들의 많은 도움을 통해, 선택되었을 때 reloaddata를 사용하지 않고 해당 cell의 백그라운드 컬러만 바꾸어 주었습니다. 모든 것이 원만하게 해결되는 것 같았으나, 다음과 같은 문제가 발생하고 있습니다. 동영상 을 보시면 알겠지만, 달력을 넘겨서 월을 바꾸면 이상한 값이 들어가 있고, 기존에 입력한 값도 전부 망가져 있습니다. 셀 들이 재사용 되면서 문제가 발생하는 것 같은데 해결법을 아시나요?…


      import UIKit import FSCalendar class CalendarViewController: UIViewController, FSCalendarDataSource, FSCalendarDelegate, FSCalendarDelegateAppearance { @IBOutlet weak var calendar: FSCalendar! @IBOutlet weak var SegmentedControl: UISegmentedControl! let DB = DataBaseAPI.init() let Quary = DataBaseQuery.init() fileprivate lazy var dateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd" return formatter }() var fillDefaultColorsArray : Array<Array<String>> = [] var fillDefaultColorsDictionary = [String : Int ]() let SegmentedBarData = ["🟩휴가","🟥훈련","🟨외출","🟦파견", "⬜️삭제"] let SegmentedBarColor = [UIColor.green,UIColor.red,UIColor.yellow,UIColor.blue , UIColor.clear] override func viewDidLoad() { super.viewDidLoad() //네비게이션바 세팅 self.navigationItem.hidesBackButton = true; self.navigationItem.leftBarButtonItem = nil; let navview = Variable_Functions.init() self.navigationItem.titleView = navview.navView //세그먼트바 세팅 SegmentedControl.removeAllSegments() SegmentedBarData.map({ text in SegmentedControl.insertSegment(withTitle: text, at: SegmentedControl.numberOfSegments, animated: false) }) SegmentedControl.selectedSegmentIndex = 0 //DB에서 불러오기 fillDefaultColorsArray = DB.query(statement: Quary.SelectStar(Tablename: "Calendar"), ColumnNumber: 2) fillDefaultColorsArray.map({ each in fillDefaultColorsDictionary.updateValue(Int(each[1])! , forKey: each[0]) }) print(fillDefaultColorsDictionary) self.calendar.dataSource = self self.calendar.delegate = self //self.calendar.cell } //날짜가 선택되어있을때 func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) { let date_string = self.dateFormatter.string(from: date) //삭제 if self.SegmentedControl.selectedSegmentIndex == 4 && fillDefaultColorsDictionary[date_string] != nil { if (DB.delete(statement: Quary.Delete(Tablename: "Calendar", Condition: "marked_date = " + "'\(date_string)'"))){ print("delete success at calander") } }else{ //기존 존재한다면 삭제하고 삽입한다. if (DB.delete(statement: Quary.Delete(Tablename: "Calendar", Condition: "marked_date = " + "'\(date_string)'"))){ print("delete success at calander before insert") } if (DB.insert(statement: Quary.insert(Tablename: "Calendar", Values: " '\(date_string)', \(SegmentedControl.selectedSegmentIndex + 1)" ))){ print("insert success at calander") } } self.calendar.deselect(date) self.calendar.cell(for: date, at: monthPosition)?.backgroundColor = SegmentedBarColor[SegmentedControl.selectedSegmentIndex] } }
      • 이 답변은 정재 이에 의해 1 year, 6 months 전에 수정됐습니다.
    • 김수호 김
      참가자
      • 글작성 : 0
      • 답글작성 : 5
      1,460 포인트

      저도 알아보다가 결국 library 소스를 조금 수정하는 방법으로 

      FSCalendarCell.m 파일에

       

      _shapeLayer.frame = CGRectMake((self.bounds.size.width-diameter)/2,
          (titleHeight-diameter)/2,
          diameter,
          diameter);
      

      이부분을 수정 해주시면 될거같습니다 … 

      백그라운드 컬러 수정 없이 그냥 selection 영역 수정 하는겁니다.

      • 이 답변은 김수호 김에 의해 1 year, 6 months 전에 수정됐습니다.
      • 이 답변은 김수호 김에 의해 1 year, 6 months 전에 수정됐습니다.
      • 이 답변은 김수호 김에 의해 1 year, 6 months 전에 수정됐습니다.
      • 이 답변은 김수호 김에 의해 1 year, 6 months 전에 수정됐습니다.
    • 야곰
      키 마스터
      • 글작성 : 37
      • 답글작성 : 539
      18,860 포인트

      셀이 재사용 된다는 것을 이해하셨다면, 셀이 재사용되는 시점에 셀의 모든 외형과 값을 초기화 한 후에 다시 새로운 값을 넣어줘야 한다는 것도 이해하실 수 있을거라 생각합니다.
      셀을 재사용하기 전에 모양을 초기화해주세요.

    • 정재 이
      참가자
      • 글작성 : 4
      • 답글작성 : 11
      1,510 포인트

      여러분들의 도움으로 문제를 해결하였습니다. 김수호님이 말씀해주신 캘린더 헤더파일을 수정하는건 제가 아직 초심자라서 정확히 어떻게 수정할 지 감이 안와서 건드리지 못하였고, 야곰님의 말처럼 셀이 재사용 될때 매번 색상을 초기화해주니 해결하였습니다! 정말 감사해요ㅠㅠ

    • hope1053
      참가자
      • 글작성 : 0
      • 답글작성 : 1
      1,040 포인트

      안녕하세요! 혹시 해당 문제 어떤 메서드 사용해서 해결하셨는지 여쭤봐도 될까요?ㅜㅜ

10 답변 글타래를 보이고 있습니다
  • 답변은 로그인 후 가능합니다.

logo landscape small

사업자번호 : 260-27-00477
통신판매업 신고번호 : 제 2020-충북청주-0663 호
고객센터 : 카카오톡채널 @yagom