$30 off During Our Annual Pro Sale. View Details »

ScrollView scroll,decelerating - iOS SDK UIkit

notoroid
September 25, 2021

ScrollView scroll,decelerating - iOS SDK UIkit

札幌iPhoneアプリ開発懇談会(Devsap) 2021年9月25日勉強会資料

notoroid

September 25, 2021
Tweet

More Decks by notoroid

Other Decks in Technology

Transcript

  1. *SJNBTV%FOTBO1MBOOJOHೳొཁ
    4DSPMM7JFX6*,JU
    4DSPMM %FDFMFSBUJOH

    View Slide

  2. iOS15ެ։͞Ε·ͨ͠

    View Slide

  3. J04Y͔Βͷڧ੍Ξοϓσʔτ͸ͳ͍ͨΊΞοϓ
    σʔτ଎౓͸଎͘ͳ͍΋ͷͷɺΞϓϦ։ൃऀଆʹ
    ͱͬͯ͸ϓϩάϥϛϯά͠΍͘͢ͳΔ࢓૊Έ͕ಋೖ

    View Slide

  4. async/await/actorͷಋೖʹΑΓεϨουؒͰͷॲ
    ཧΛؾʹ͢Δඞཁ͕ݮΓSwiftUI(ͱ͍͏͔iOSωΠ
    ςΟϒΞϓϦ։ൃ)ͷֶशίετ͕Լ͕Γ·ͨ͠ɻ

    View Slide

  5. SwiftUI Λొ৔ͷࠒ(2019)͔
    Βਪ͍ͯ͠Δ౰ํͰ͕͢ɺ

    View Slide

  6. ͜͜Ζ͸SwiftUIΛ཭Ε

    UIKit ʹ໭͍ͬͯͨɻ

    View Slide

  7. Կނ

    View Slide

  8. 6*,JUͰ΍Γ͜࢒ͨ͜͠
    ͱ͕͋Δ͔Βͩ
    ຊԻ
    4XJGU6*Ͱཉ͍͕͠4XJGU6*Ͱ࣮ݱͰ͖ͳ͍͔Β

    View Slide

  9. *OGJOJU-PPQ)FBEFS
    ແݶʹεΫϩʔϧͰ͖Δϔομ
    w ࠨӈํ޲ʹεΫϩʔϧՄೳ
    w ϝχϡʔ͕ແݶʹදࣔ͞Ε
    ͍ͯΔΑ͏ʹϔομ߲໨͕
    εΫϩʔϧ
    w தԝʹ͋Δ߲໨͕બ୒த
    w ϠΫΦΫΞϓϦ ೥
    ݄ݱࡏ
    ͷϝχϡʔ

    View Slide

  10. *OGJOJU-PPQ)FBEFS
    w ແݶϧʔϓϔομʔ͸ΦʔϓϯιʔεϕʔεͰ͍͔ͭ͘ଘࡏ
    w 6*$PMMFDUJPO7JFXϕʔε
    w %BUB4PVSDFEFMFHBUFΛ࢖ͬͯಈతʹΧϥϜੜ੒
    w ਺ݸͷϝχϡʔ߲໨Λදࣔ͢Δ͚ͩͰ6*$PMMFDUJPO7JFXΛ࢖͏ඞ
    ཁ͕͋Δͷ͔
    w ΋ͬͱγϯϓϧʹ ͭ·Γ6*4DSPMM7JFX
    Ͱ࣮ݱͰ͖ͳ͍͔

    View Slide

  11. 6*4DSPMMʹ͍ͭͯ
    ߟ͑ͯΈΔ

    View Slide

  12. 6*4DSPMM7JFX

    J04ͷ࢖͍ͪ͝͝ͷྑ͞Λܾఆ͚ͮͨ6*ύʔπ
    w J04 J1IPOF04
    ͷࠒ͔Βଘࡏ
    w Ϣʔβʔͷλονૢ࡞ʹ௥ਵ͢ΔεΫϩʔϧ
    w ίϯςϯπ຤୺·Ͱ౸ୡͨ͠ࡍͷό΢ϯε
    w Ԡ༻6*ଟ਺
    w 8,8FC7JFXɺ6*5BCMF7JFXɺ6*$PMMFDUJPO7JFX
    w աڈʹ͸.BQ΋࢖༻

    View Slide

  13. 6*4DSPMM7JFX

    J04ͷ࢖͍ͪ͝͝ͷྑ͞Λܾఆ͚ͮͨ6*ύʔπ
    w ΞϓϦ։ൃͰ΋ෳࡶͳ࢓૊Έ
    w εΫϩʔϧίϯςϯπͷ෯ߴ͞ͷऔѻ͕೥ʑมԽ
    w "VUP4J[JOHˠ$POTUSBJOUˠ"ODIPSͱ೥ʑ੔ཧ
    w ίϯςϯπྖҬͷτϥϒϧ
    w J04ʙεςʔλεόʔྖҬมߋΛ΋Ζʹड͚Δ
    w εςʔλεόʔ͔ΒϊονྖҬ΁ͱมԽ
    w ෳ਺ϓϩύςΟͷ૊Έ߹ΘͤͰڍಈ͕มԽ
    w %FMFHBUFͰͷදࣔྖҬ੍ޚͷϊ΢ϋ΢ඞཁ

    View Slide

  14. 6*4DSPMM7JFXͱ೿ੜΫϥε
    w 6*,JU͸యܕతͳΫϥεϥ
    ΠϒϥϦ
    w ೿ੜݩΫϥεͷػೳΛ೿ੜ
    ݩ্͕ॻ͖͢Δ
    w ೿ੜ͕܁Γฦ͞ΕΔͱຊདྷ
    ͷػೳ͕࢖͑Δ͔೺Ѳͮ͠
    Β͘ͳΔ
    ೿ੜݩ
    ೿ੜઌ

    View Slide

  15. 6*4DSPMM7JFXͷػೳ্ॻ͖ঢ়گ
    6*4DSPMM7JFXͷ೿ੜΫϥεͰԿ͕࢖͑Δ͔
    ߟ͑Δඞཁ͋Γ

    View Slide

  16. 6*4DSPMM7JFXͷػೳ্ॻ͖ঢ়گ
    6*4DSPMM7JFXͷ೿ੜΫϥεͰԿ͕࢖͑Δ͔
    ߟ͑Δඞཁ͋Γ
    EFMFHBUF͸࢖༻Մೳ
    δΣενϟʔҎ֎͸֓Ͷ
    ར༻Մೳ

    View Slide

  17. 6*4DSPMM7JFX%FMFHBUF
    6*4DSPMM7JFX಺ͰͷΠϕϯτΛัଊ͢ΔEFMFHBUF
    w 4DSPMMΠϕϯτ
    w εΫϩʔϧ։࢝ऴྃΠϕϯτ
    w ར༻ऀ6*ଆͷશͯͷεΫϩʔϧΠϕϯτ͕ൃੜ
    w ζʔϜ։࢝ऴྃΠϕϯτ
    w %FDFMFSBUJOH։࢝ऴྃΠϕϯτ
    w Ϣʔβʔͷૢ࡞ޙʹό΢ϯυಈ࡞ͷ։࢝ऴྃΛ௨஌
    w εΫϩʔϧΛτοϓʹҠಈ͢Δ͔ͷΠϕϯτ εςʔλεྖҬͷλ
    οϓ

    View Slide

  18. 6*4DSPMM7JFX%FMFHBUF

    4DSPMMͱ%FDFMFSBUJOHͷؔ܎
    w 4DSPMMΠϕϯτ
    w Ϣʔβʔ͕λονૢ࡞Ͱ
    w %FDFMFSBUJOHΠϕϯτ
    w Ճ଎౓͋Γͷλονૢ࡞ޙʹɺ4DSPMM7JFX͕ຊདྷ͋Δ΂͖Ґஔ
    ʹίϯςϯπ͕໭Δ·ͰͷΠϕϯτ
    w %FDFMFSBUJOH͕ऴྃ͢Δ·Ͱը໘্ͷಈ͖͸ࢭ·Βͳ͍

    View Slide

  19. ͜͜·ͰΛ౿·͑ͯ
    ແݶϧʔϓΛ࣮ݱ͢Δ

    View Slide

  20. αϯϓϧίʔυ

    View Slide

  21. IUUQTHJUIVCDPNOPUPSPJE
    *OGJOJUF)FBEFS%FNP

    View Slide

  22. 6*4DSPMM7JFXͰແݶεΫϩʔϧΛ࣮ݱᶃ
    4DSPMMຖʹҐஔௐ੔ɺ%FDFMFSBUJOHޙʹਖ਼نԽ

    View Slide

  23. 6*4DSPMM7JFXͰແݶεΫϩʔϧΛ࣮ݱᶄ
    4DSPMMຖʹҐஔௐ੔ɺ%FDFMFSBUJOHޙʹਖ਼نԽ

    View Slide

  24. 6*4DSPMM7JFXͰແݶεΫϩʔϧΛ࣮ݱᶄ
    4DSPMMຖʹҐஔௐ੔ɺ%FDFMFSBUJOHޙʹਖ਼نԽ
    JO
    fi
    OJUF-PPQ7JFX্ͷ4UBDL7JFXͷ9࣠Λௐ
    ੔ͯ͠ݶΓ͋ΔϔομཁૉΛ࠶ར༻͢Δ
    JO
    fi
    OJUF-PPQ7JFX͸4DSPMM7JFX੍͕ޚ͢Δ

    View Slide

  25. 6*4DSPMM7JFXͰແݶεΫϩʔϧΛ࣮ݱᶅ
    4DSPMMຖʹҐஔௐ੔ɺ%FDFMFSBUJOHޙʹਖ਼نԽ
    4DSPPM7JFXͷྖҬΛϔομʔͷΧϥϜ
    ෯ͱ͠ɺDMJQ5P#PVOEΛ֦͛ͯࢠཁૉΛ
    දࣔɺλονՄೳͳྖҬ΋֦͓͛ͯ͘

    View Slide

  26. extension InfiniteLoopHeaderView: UIScrollViewDelegate {





    // Decelerating΁ͷରԠ


    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {


    // εΫϩʔϧҐஔͷਖ਼نԽ͕ߦΘΕ͍ͯͳ͍৔߹


    guard scrollNormalizedPosition != 0 else {


    return


    }


    // ίϯςϯπͷதԝҐஔΛऔಘ


    let scrollViewCenter = scrollView.superview!.convert(scrollView.center, to: contentView)


    // தԝҐஔؚ͕·ΕΔۣܗ৘ใΛݩʹϔομʔཁૉͷΠϯσοΫεΛܭࢉ


    var targetIndex: Int = -1


    for index in 0..<(leftOverrun + elementCount + rightOverrun) {


    let hitTestRect = CGRect(origin: CGPoint(x: CGFloat(index) * scrollView.bounds.width, y: 0),
    size: scrollView.bounds.size)


    if hitTestRect.contains(scrollViewCenter) {


    targetIndex = index


    }


    }




    // ಘΒΕͨΠϯσοΫεΛݩʹΠϯσοΫε৘ใΛਖ਼نԽ


    let position = targetIndex - leftOverrun


    let loopIndex = (elementCount + ( (position) % elementCount)) % elementCount


    selectedIndex = loopIndex




    // ͜͜ͰεΫϩʔϧॲཧΛϓϩςΫτ͢Δ(scrollNormalizedPosition͕มߋ͞Εͯ͠·͏ՄೳੑΛආ͚ΔͨΊ)


    skipDidScroll = true


    self.scrollView.contentOffset = CGPoint(x: self.scrollView.bounds.width *
    CGFloat(centerForFiniteLoop() + selectedIndex), y: 0)


    skipDidScroll = false




    scrollNormalizedPosition = 0


    centerXConstraint.constant = 0


    }


    }

    View Slide

  27. extension InfiniteLoopHeaderView: UIScrollViewDelegate {





    // εΫϩʔϧ΁ͷରԠ


    func scrollViewDidScroll(_ scrollView: UIScrollView) {


    // skipDidScroll͞Ε͍ͯΔ৔߹͸scrollViewDidEndDecelerating Ͱͷ


    guard skipDidScroll != true else {


    return


    }




    // ScrollViewͷcontentOffsetͱscrollNormalizedPosition͔ΒҐஔΛಘΔ


    let plainPosition = Int(ceil( (scrollView.contentOffset.x / scrollView.bounds.width) -
    CGFloat(centerForFiniteLoop()) + CGFloat(scrollNormalizedPosition) ) )




    if plainPosition <= leftSafeArea {


    // ϔομʔࠨͷ҆શྖҬΛ௒͍͑ͯͨ৔߹͸scrollNormalizedPosition ʹҐஔΛ֨ೲ͠contentView ͷҐஔΛͣΒ͢


    scrollNormalizedPosition = scrollNormalizedPosition + -plainPosition + (elementCount -
    visibleColumnNumber)


    centerXConstraint.constant = CGFloat(-scrollNormalizedPosition) * scrollView.bounds.width


    } else if plainPosition >= rightSafeArea {


    // ϔομʔӈͷ҆શྖҬΛ௒͍͑ͯͨ৔߹͸scrollNormalizedPosition ʹҐஔΛ֨ೲ͠contentView ͷҐஔΛͣΒ͢


    scrollNormalizedPosition = scrollNormalizedPosition + -plainPosition


    centerXConstraint.constant = CGFloat(-scrollNormalizedPosition) * scrollView.bounds.width


    } else {


    // ͦͷଞͷ৔߹͸௨ৗॲཧɻબ୒ΠϯσοΫεΛมߋ


    let lIndex = (elementCount + (plainPosition % elementCount)) % elementCount


    selectedIndex = lIndex


    }


    }


    }

    View Slide

  28. ·ͱΊ

    View Slide

  29. ·ͱΊ
    w4XJGU6*Ͱ࣮ݱͰ͖ͳ͍6*Λ6*,JUͰ࡞Γ·ͨ͠
    wΦʔϓϯιʔεطଘͷ΋ͷΑΓγϯϓϧͳ6*ύʔπ
    Λ໨ࢦ͠·ͨ͠
    w6*ύʔπΛ࡞੒ʹ6*4DSPMM7JFXΛ࢖༻͠·ͨ͠
    w6*4DSPMM7JFXͷ4DSPMMΠϕϯτ͸Ϣʔβʔૢ࡞ɺՃ
    ଎౓ʹΑΔό΢ϯυؔ܎ͳ͠ʹൃੜ͠·͢
    w6*4DSPMM7JFX͕׬શʹ੩ࢭ͢Δͷ͸%FDFMFSBUJOH
    ΠϕϯτऴྃޙͰ͢

    View Slide