【SwiftUI】잔디 달력 만들었다

13446 단어 SwiftSwiftUI
SwiftUI로 히트 맵 형식의 캘린더(잔디, 잔디라든지 말해지고 있는 녀석)를 만들어 보았으므로 간단한 구조입니다만 메모해 두려고 생각합니다.

MMHeatmap 라이브러리




절각 라이브러리를 만들었으므로 학습도 겸해 Swift Package Manager에 대응해 공개해 보았습니다.
  • 리포지토리: htps : // 기주 b. 코 m / s - 1 - 0 / m m tma p
    도입 방법이라든가 리포지토리의 README.md에 있으므로 생략합니다.

  • View 구조



    최하층부터 순서대로 설명합니다.

    일주일용 VStack



    우선 1주간분(7개의 셀)을 다음과 같은 느낌으로 VStack으로 세로로 늘어놓습니다.
    VStack(spacing:2){
                ForEach(0..<7){ i in
                    RoundedRectangle(cornerRadius: 2).frame(width: 10,height: 10).modifier(CellColorModifier(isRange: (i >= start && i <= end ) , value: values[i], maxValue: maxValue,minColor: style.minCellColor,baseColor: style.baseCellColor))
                }
            }
    

    MMHeatmapColumnView.swift

    미리보기하기 어렵기 때문에 이 계층에서는 Date 형은 취급하지 않고, 위의 View 로부터 주어진 표시 범위와 값에 따라 셀의 색을 결정합니다.
    ※CellColorModifier에 대해서는 후술합니다.

    1개월용 HStack



    그런 다음 HStack에서 일주일 동안 VStack을 일주일 동안 정렬합니다.
    1개월분의 주수의 특정은, 다음 달의 0일(즉 그 달의 마지막 날)을 설정한 DateComponents를 Date형으로 한 후, Calendar로 주수를 요구할 수 있습니다.
    var comp = DateComponents()
    comp.year = 2021
    comp.month = MM + 1
    comp.day = 0
    let date = calendar.date(from: comp)!
    let weeks = calendar.component(.weekOfMonth, from: date)
    

    몇 달 동안 HStack



    마지막으로 1개월용 HStack을 지정 범위의 월수분 늘어놓습니다.

    셀의 색 결정



    데이터가 되는 수치 배열중에서 최대치의 색을 baseColor, 최소치 0의 색을 minColor로서 baseColor와 minColor의 중간색을 구합니다.
    또한, 데이터의 값을 nil로 했을 경우는 셀의 색을 투명(Color.clear)으로 설정하고 있습니다.

    다음 수정자
    saturation = (saturation - secondSaturation) * pct + secondSaturation
    brightness = (brightness - secondBrightness) * pct + secondBrightness
    

    의 부분에서 중간색(채도, 명도)을 결정하고 있습니다.
    (이 코드는 색조의 중간 색을 요구하지 않았습니다.)
    fileprivate struct CellColorModifier:ViewModifier {
        init(isRange:Bool,value:Int?,maxValue:Int,minColor:UIColor,baseColor:UIColor) {
            self.isRange = isRange
            if let v = value{
            let pct:CGFloat = CGFloat(v) / CGFloat(maxValue)
                var secondHue:CGFloat = 0
                var secondSaturation:CGFloat = 0
                var secondBrightness:CGFloat = 0
                var secondAlpa:CGFloat = 0
            minColor.getHue(&secondHue, saturation: &secondSaturation, brightness: &secondBrightness, alpha: &secondAlpa)
            var hue:CGFloat = 0
            var saturation:CGFloat = 0
            var brightness:CGFloat = 0
            var alpha:CGFloat = 0
            baseColor.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
            saturation = (saturation - secondSaturation) * pct + secondSaturation
            brightness = (brightness - secondBrightness) * pct + secondBrightness
            self.rangeColor = Color(UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha))
            }else{
                self.rangeColor = Color(UIColor.clear)
            }
        }
        let isRange:Bool
        let rangeColor:Color
        func body(content: Content) -> some View {
            Group{
            if(isRange){
                content.foregroundColor(rangeColor)
            }else{
                content.foregroundColor(Color.clear)
            }
            }
        }
    }
    

    Swift Package



    다음 기사를 참고했습니다. jjjkkkjjj님께 감사드립니다.
    htps : // 이 m / j j k j / ms / 727517263292 Ae 7 A 3 A 87

    덧붙여서 SwiftUI의 미리보기를 할 때에 대량의 에러가 나오는 경우는, 미리 보기하는 파일 이외를 닫아 가상 단말을 Mac로부터 iPhone이나 iPad로 했다고 고쳤습니다.

    끝에



    이상으로 기본적인 잔디 달력을 만들 수 있었습니다.
    개선할 의욕이 생기면 GeometryReader를 사용하여 MMHeatmap을 화면 크기에 맞는 캘린더로 개선하고 싶습니다.

    좋은 웹페이지 즐겨찾기