Upgrade to Pro — share decks privately, control downloads, hide ads and more …

今更だけどUIKitで型パラメータのインジェクトを利用してViewのレイアウトをしてみよう

Avatar for Taiki Suzuki Taiki Suzuki
September 12, 2022

 今更だけどUIKitで型パラメータのインジェクトを利用してViewのレイアウトをしてみよう

Avatar for Taiki Suzuki

Taiki Suzuki

September 12, 2022
Tweet

More Decks by Taiki Suzuki

Other Decks in Programming

Transcript

  1.   ڞ௨ͷViewͰදݱͨ͠৔߹ͷྫ final class SummaryView: UIView { private let

    stackView: UIStackView private let titleLabel: UILabel private var subTextLabel: UILabel? private var additionalView: UIView? }
  2.   enumͰදݱͨ͠৔߹ͷྫ public enum SummaryCombination: Hashable { // MARK:

    - Basic case subTextTopBasic(startAt: String, title: String) case subTextSecondBasic(title: String, broadcastTime: String) case noSubTextBasic(title: String) // MARK: - Coin case subTextSecondCoin(title: String, duration: String, tag: Tag?, coin: Int?) case noSubTextCoin(title: String, coin: Int?, expirationTime: String?) // MARK: - ViewingType case subTextTopViewingType(seasonName: String, title: String, tag: Tag?, expirationTime: String?) case subTextSecondViewingType(title: String, broadcastTime: String, tag: Tag?, expirationTime: String?) case noSubTextViewingType(title: String, tag: Tag?, expirationTime: String?) }
  3.   enumͰදݱͨ͠৔߹ͷྫ public enum SummaryCombination: Hashable { case subTextTopBasic(startAt:

    String, title: String) case subTextSecondBasic(title: String, broadcastTime: String) case noSubTextBasic(title: String)
  4.   enumͰදݱͨ͠৔߹ͷྫ public enum SummaryCombination: Hashable { case subTextSecondCoin(title:

    String, duration: String, tag: Tag?, coin: Int?) case noSubTextCoin(title: String, coin: Int?, expirationTime: String?)
  5.   enumͰදݱͨ͠৔߹ͷྫ public enum SummaryCombination: Hashable { case subTextTopViewingType(seasonName:

    String, title: String, tag: Tag?, expirationTime: String?) case subTextSecondViewingType(title: String, broadcastTime: String, tag: Tag?, expirationTime: String?) case noSubTextViewingType(title: String, tag: Tag?, expirationTime: String?)
  6.   enumͰදݱͨ͠৔߹ͷྫ final class SummaryView: UIView { ... func

    configure(_ combination: SummaryCombination) { switch combination { case let .subTextTopBasic(startAt, title): titleLabel.text = title titleLabel.numberOfLines = 2 configureSubTextLabel(text: startAt, position: 0) additionalView?.removeFromSuperview() case let .subTextSecondBasic(title, broadcastTime): ... case let .noSubTextBasic(title): ... case let .subTextSecondCoin(title, duration, tag, coin): ... case let .noSubTextCoin(title, coin, expirationTime): ... case let .subTextTopViewingType(seasonName, title, tag, expirationTime): ... case let .subTextSecondViewingType(title, broadcastTime, tag, expirationTime): ... case let .noSubTextViewingType(title, tag, expirationTime): ... } } }
  7.   enumͰදݱͨ͠৔߹ͷྫ final class SummaryView: UIView { titleLabel.text =

    title titleLabel.numberOfLines = 2 configureSubTextLabel(text: startAt, position: 0) additionalView?.removeFromSuperview()
  8.   ܕύϥϝʔλͰදݱͨ͠৔߹ͷྫ protocol SummaryRow { static func subTextLabelAndInsertionIndex() ->

    (UILabel, Int)? } enum SubTextTop: SummaryRow { static func subTextLabelAndInsertionIndex() -> (UILabel, Int)? { (UILabel(frame: .zero), 0) } } enum SubTextSecond: SummaryRow { static func subTextLabelAndInsertionIndex() -> (UILabel, Int)? { (UILabel(frame: .zero), 1) } } enum NoSubText: SummaryRow { static func subTextLabelAndInsertionIndex() -> (UILabel, Int)? { nil } }
  9.   ܕύϥϝʔλͰදݱͨ͠৔߹ͷྫ protocol SummaryColumn { associatedtype AdditionalView: UIView static

    func additionalView() -> AdditionalView? } enum Basic: SummaryColumn { static func additionalView() -> UIView? { nil } } enum Coin: SummaryColumn { static func additionalView() -> UIView? { nil } } enum ViewingType: SummaryColumn { static func additionalView() -> TagTextView? { TagTextView(frame: .zero) } }
  10.   ܕύϥϝʔλͰදݱͨ͠৔߹ͷྫ protocol SummaryColumn { associatedtype AdditionalView: UIView static

    func additionalView() -> AdditionalView? } ྻͰڞ௨ͳΧελϜ7JFXΛBTTPDJBUFE5ZQFͰఆٛ
  11.   ܕύϥϝʔλͰදݱͨ͠৔߹ͷྫ protocol SummaryCombination { associatedtype Row: SummaryRow associatedtype

    Column: SummaryColumn associatedtype AdditionalView: UIView static func numberOfTitleLines() -> Int static func additionalView() -> AdditionalView? static func subTextColor() -> UIColor? } ߦͱྻͷ૊Έ߹ΘͤΛදݱ͢ΔQSPUPDPM
  12.   ܕύϥϝʔλͰදݱͨ͠৔߹ͷྫ enum SubTextTopBasic: SummaryCombination { typealias Row =

    SubTextTop typealias Column = Basic static func numberOfTitleLines() -> Int { 2 } static func additionalView() -> UIView? { nil } } enum SubTextSecondCoin: SummaryCombination { typealias Row = SubTextSecond typealias Column = Coin static func numberOfTitleLines() -> Int { 2 } static func additionalView() -> TagCoinView? { TagCoinView(frame: .zero) } } enum SubTextTopViewingType: SummaryCombination { typealias Row = SubTextTop typealias Column = ViewingType static func numberOfTitleLines() -> Int { 2 } static func additionalView() -> Column.AdditionalView? { Column.additionalView() } }
  13.   ܕύϥϝʔλͰදݱͨ͠৔߹ͷྫ enum SubTextTopBasic: SummaryCombination { typealias Row =

    SubTextTop typealias Column = Basic static func numberOfTitleLines() -> Int { 2 } static func additionalView() -> UIView? { nil } }
  14.   ܕύϥϝʔλͰදݱͨ͠৔߹ͷྫ enum SubTextTopBasic: SummaryCombination { typealias Row =

    SubTextSecond typealias Column = Coin static func numberOfTitleLines() -> Int { 2 } static func additionalView() -> TagCoinView? { TagCoinView(frame: .zero) } }
  15.   ܕύϥϝʔλͰදݱͨ͠৔߹ͷྫ enum SubTextTopBasic: SummaryCombination { typealias Row =

    SubTextTop typealias Column = ViewingType static func numberOfTitleLines() -> Int { 2 } static func additionalView() -> Column.AdditionalView? { Column.additionalView() } }
  16.   ܕύϥϝʔλΛར༻ͨ͠ڞ௨ͷViewͷྫ final class SummaryView<Combination: SummaryCombination>: UIView { private

    let stackView: UIStackView private let titleLabel: UILabel private let subTextLabel: UILabel? private let additionalView: Combination.AdditionalView? override init(frame: CGRect) { let subTextLabelAndInsertionIndex = Combination.Row.subTextLabelAndInsertionIndex() self.subTextLabel = subTextLabelAndInsertionIndex?.0 self.additionalView = Combination.additionalView() super.init(frame: frame) titleLabel.numberOfLines = Combination.numberOfTitleLines() backgroundColor = .black ... stackView.addArrangedSubview(titleLabel) if let (subTextLabel, index) = subTextLabelAndInsertionIndex { subTextLabel.textColor = Combination.subTextColor() subTextLabel.font = .systemFont(ofSize: 12) stackView.insertArrangedSubview(subTextLabel, at: index) } if let additionalView = additionalView { stackView.addArrangedSubview(additionalView) } } }
  17.   ܕύϥϝʔλΛར༻ͨ͠ڞ௨ͷViewͷྫ final class SummaryView<Combination: SummaryCombination>: UIView { private

    let additionalView: Combination.AdditionalView? override init(frame: CGRect) let subTextLabelAndInsertionIndex = Combination.Row.subTextLabelAndInsertionIndex() self.additionalView = Combination.additionalView() titleLabel.numberOfLines = Combination.numberOfTitleLines() subTextLabel.textColor = Combination.subTextColor() 6*7JFXͷJOJU GSBNF ΛΦʔόʔϥΠυ͍ͯ͠Δ ͷͰɺJOJUJBMJ[FS͔Β͸ґଘΛ஫ೖ͢Δ͜ͱ͸Ͱ͖ ͳ͍͕ɺܕύϥϝʔλ͔Β஫ೖ͢Δ͜ͱ͕Ͱ͖Δ
  18.   ܕύϥϝʔλΛར༻ͨ͠ڞ௨ͷViewͷྫ final class SummaryView<Combination: SummaryCombination>: UIView { private

    let titleLabel: UILabel titleLabel.numberOfLines = Combination.numberOfTitleLines() stackView.addArrangedSubview(titleLabel)
  19.   ܕύϥϝʔλΛར༻ͨ͠ڞ௨ͷViewͷྫ final class SummaryView<Combination: SummaryCombination>: UIView { private

    let subTextLabel: UILabel? let subTextLabelAndInsertionIndex = Combination.Row.subTextLabelAndInsertionIndex() self.subTextLabel = subTextLabelAndInsertionIndex?.0 if let (subTextLabel, index) = subTextLabelAndInsertionIndex { subTextLabel.textColor = Combination.subTextColor() subTextLabel.font = .systemFont(ofSize: 12) stackView.insertArrangedSubview(subTextLabel, at: index) }
  20.   ܕύϥϝʔλΛར༻ͨ͠ڞ௨ͷViewͷྫ final class SummaryView<Combination: SummaryCombination>: UIView { private

    let additionalView: Combination.AdditionalView? self.additionalView = Combination.additionalView() if let additionalView = additionalView { stackView.addArrangedSubview(additionalView) } BTTPDJBUFE5ZQFͰܕΛఆ͍ٛͯ͠ΔͷͰɺར༻ ઌͰΩϟετͤͣʹΧελϜ7JFXͷϝιου౳ʹ ΞΫηεͰ͖Δ
  21.   ܕύϥϝʔλΛར༻ͨ͠ڞ௨ͷViewͷྫ extension SummaryView where Combination == SubTextTopBasic {

    func configure(startAt: String, title: String) { setTitle(title) setSubText(startAt) } } extension SummaryView where Combination == SubTextSecondCoin { func configure(title: String, duration: String, tag: Tag?, coin: Int?) { setTitle(title) setSubText(duration) additionalView?.configure(tag: tag, coin: coin) } } extension SummaryView where Combination == SubTextTopViewingType { func configure(seasonName: String, title: String, tag: Tag?, expirationTime: String?) { setTitle(title) setSubText(seasonName) additionalView?.configure(tag: tag, text: expirationTime) } }
  22.   ܕύϥϝʔλΛར༻ͨ͠ڞ௨ͷViewͷྫ extension SummaryView where Combination == SubTextTopBasic {

    func configure(startAt: String, title: String) { setTitle(title) setSubText(startAt) } } extension SummaryView where Combination == SubTextSecondCoin { func configure(title: String, duration: String, tag: Tag?, coin: Int?) { setTitle(title) setSubText(duration) additionalView?.configure(tag: tag, coin: coin) } } extension SummaryView where Combination == SubTextTopViewingType { func configure(seasonName: String, title: String, tag: Tag?, expirationTime: String?) { setTitle(title) setSubText(seasonName) additionalView?.configure(tag: tag, text: expirationTime) } } δΣωϦοΫXIFSF۟Ͱ$PNCJOBUJPOΛࢦఆͯ͠ $PNCJOBUJPO͝ͱͷϝιουΛఆٛ͠ɺ಺෦Ͱ͸ ܕ͕֬ఆ͍ͯ͠ΔBEEUJPOBM7JFXͷ࣮૷Λݺͼग़ ͯ͠ϨΠΞ΢τΛߋ৽͢Δ
  23.   enumͱܕύϥϝʔλͷύλʔϯͰUICollectionViewͷdequeueͷҧ͍ // enumͰදݱͨ͠৔߹ public func collectionView(_ collectionView: UICollectionView,

    cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let combination = combinations[indexPath.row] let result = collectionView.reusable.dequeueReusableView(ListView<SummaryView>.self, for: indexPath) result.view.summaryView.configure(combination) return result.cell } // ܕύϥϝʔλͰදݱͨ͠৔߹ public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { switch viewDataModels[indexPath.row] { case let .subTextTopBasic(startAt, title): let result = collectionView.reusable.dequeueReusableView(ListView<SummaryView<SubTextTopBasic>>.self, for: indexPath) result.view.summaryView.configure(startAt: startAt, title: title) return result.cell case let .subTextSecondBasic(title, broadcastTime): let result = collectionView.reusable.dequeueReusableView(ListView<SummaryView<SubTextSecondBasic>>.self, for: indexPath) result.view.summaryView.configure(title: title, broadcastTime: broadcastTime) return result.cell ... } }
  24.   enumͱܕύϥϝʔλͷύλʔϯͰUICollectionViewͷdequeueͷҧ͍ // enumͰදݱͨ͠৔߹ let result = collectionView.reusable.dequeueReusableView(ListView<SummaryView>.self, for:

    indexPath) result.view.summaryView.configure(combination) return result.cell ಉҰͷ7JFXΛ࢖͍ճͯ͠ɺFOVNͷDBTFʹΑͬͯ ಺෦ͰϨΠΞ΢τΛมߋ͍ͯ͠Δ
  25.   enumͱܕύϥϝʔλͷύλʔϯͰUICollectionViewͷdequeueͷҧ͍ // enumͰදݱͨ͠৔߹ switch viewDataModels[indexPath.row] { case let

    .subTextTopBasic(startAt, title): let result = collectionView.reusable.dequeueReusableView(ListView<SummaryView<SubTextTopBasic>>.self, for: indexPath) result.view.summaryView.configure(startAt: startAt, title: title) return result.cell case let .subTextSecondBasic(title, broadcastTime): let result = collectionView.reusable.dequeueReusableView(ListView<SummaryView<SubTextSecondBasic>>.self, for: indexPath) result.view.summaryView.configure(title: title, broadcastTime: broadcastTime) return result.cell ܕύϥϝʔλͷύλʔϯ͝ͱʹEFRVFVF͢Δ͜ͱʹ ͳΓɺϨΠΞ΢τ͕֬ఆͨ͠ঢ়ଶͰඞཁͳ෦෼ͷΈΛ ඞཁͳϝιου͚ͩݺͼग़ͯ͠ߋ৽Ͱ͖Δ
  26.   os_signpostͰcon fi gureͷॲཧ࣌ؒΛൺֱ &OVN 5JNFT 5ZQF1BSBNFUFS 5JNFT 4VC5FYU5PQ#BTJD

    ЖT  ЖT  4VC5FYU4FDPOE#BTJD ЖT  ЖT  /P4VC5FYU#BTJD NT  ЖT  4VC5FYU4FDPOE$PJO NT  ЖT  /P4VC5FYU$PJO NT  ЖT  4VC5FYU5PQ7JFXJOH5ZQF NT  ЖT  4VC5FYU4FDPOE7JFXJOH5ZQF NT  ЖT  /P4VC5FYU7JFXJOH5ZQF NT  ЖT 
  27.   os_signpostͰcon fi gureͷॲཧ࣌ؒΛൺֱ &OVN 5JNFT 5ZQF1BSBNFUFS 5JNFT 4VC5FYU5PQ#BTJD

    ЖT  ЖT  4VC5FYU4FDPOE#BTJD ЖT  ЖT  /P4VC5FYU#BTJD NT  ЖT  4VC5FYU4FDPOE$PJO NT  ЖT  /P4VC5FYU$PJO NT  ЖT  4VC5FYU5PQ7JFXJOH5ZQF NT  ЖT  4VC5FYU4FDPOE7JFXJOH5ZQF NT  ЖT  /P4VC5FYU7JFXJOH5ZQF NT  ЖT  ڞ௨ͷ7JFX࣮૷͍ͯ͠Δͷ͸ಉ͕ͩ͡ɺ$PNCJOBUJPO ͝ͱͷδΣωϦοΫͳܕΛར༻ͯ͠ɺϨΠΞ΢τ͕֬ఆ͠ ͨঢ়ଶͷ7JFXΛར༻Ͱ͖ΔͷͰɺϨΠΞ΢τͷߋ৽͸΄ ΅͞Εͣʹจࣈྻ౳ͷߋ৽ͷΈʹͳΔͨΊ଎͍