기획, 디자인 변경에 강한 카드뷰 만들기 - ios tech talk 2017

35

Upload: wanbok-choi

Post on 21-Mar-2017

24 views

Category:

Mobile


2 download

TRANSCRIPT

Page 2: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
Page 3: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
Page 4: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
Page 5: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

class CardTableViewCell: UITableViewCell

Page 6: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

class ProductCardView: UIViewclass CardTableViewCell: UITableViewCell

Page 7: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
Page 8: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
Page 9: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
Page 10: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

protocol CardViewModelType { var cardType: CardType { get } var title: String? { get } var subTitle: String? { get } var rating: Double? { get } var reviewCount: Int? { get } var profileImageButtonViewModel: ProfileImageButtonViewModelType? { get } var coverImageURLString: String? { get } var tags: [String]? { get } // Input var didWish: PublishSubject<Bool>? { get } // Output var wish: Driver<Bool>? { get } var disposeBag: DisposeBag { get } }

enum CardType { case small, big var cellSize: CGSize { switch self { case .small: return CGSize(width: 160, height: 200) case .big: return CGSize(width: 250, height: 230) } } }

Page 11: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

struct CardViewModel: CardViewModelType { init(cardType: CardType, product: Product) { self.cardType = cardType self.title = product.title self.subTitle = product.catchPhrase self.coverImageURLString = product?.imageURLs?.first self.profileImageButtonViewModel = { guard let host = product.host else { return nil } return ProfileImageButtonViewModel(profileType: .host(host), size: cardType.circleImageSize) }() self.rating = product.rating self.reviewCount = product.reviewCount self.tags = { if let tags = product.areaTags? .filter({ $0.label?.characters.count ?? 0 > 0 }) .map({ $0.label ?? "" }), tags.count > 0 { return tags } else if let tags = product.locationTags? .filter({ $0.label?.characters.count ?? 0 > 0 }) .map({ $0.label ?? "" }), tags.count > 0 { return tags } else { return nil } }() ...

Page 12: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

... if let product = product, let productId = product.id { self.wish = self.didWish?.asDriver(onErrorJustReturn: false) .withLatestFrom(Driver.just(productId)) { ($0, $1) } .flatMap { w, pId in Router.ProductWishToggle(["productId": pId]).request .rx.json() .asDriver(onErrorJustReturn: [:]) .map { (JSON($0)["success"].bool ?? false) ? !w : w } } .startWith(product.isWished) // Sync wishes self.wish?.withLatestFrom(Driver.just(product)) { ($0, $1) } .drive(onNext: { $0.1.isWished = $0.0 }) .addDisposableTo(self.disposeBag) } else { self.wish = nil } } }

Page 13: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
Page 14: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

protocol CardViewType { var coverImageView: UIImageView? { get } ... }

extension CardType: CardViewType { var coverImageView: UIImageView? { switch self { case .big: let imageView = UIImageView(frame: self.coverImageSize.rect) ... return imageView case .small: let imageView = UIImageView(frame: self.coverImageSize.rect) ... return imageView } } ... }

Page 15: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

final class CardView: UIView, CardViewType { let coverImageView: UIImageView? ... private var disposeBag: DisposeBag required init(on superview: UIView, with viewModel: CardViewModelType, inset: UIEdgeInsets = .zero) { self.coverImageView = viewModel.cardType.coverImageView ... super.init(frame: viewModel.cardType.cellSize.rect)

superview.addSubview(self) self.snp.makeConstraints { $0.size.equalTo(viewModel.cardType.cellSize) $0.edges.equalTo(superview.snp.edges).inset(inset) }

self.configure(by: viewModel) self.configureLayout(by: viewModel) } ...

Page 16: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

func configure(by viewModel: CardViewModelType) { self.disposeBag = viewModel.disposeBag self.coverImageView?.setImage( with: viewModel.coverImageURLString, transformation: viewModel.cardType.coverImageSize.cloudinaryTransformation ) ...

self.favoriteButton?.removeTarget(self, action: nil, for: .allEvents) if let favoriteButton = self.favoriteButton { let needUserName = User.notification .map { $0.name?.isEmpty ?? true } let tapFollowButton = favoriteButton.rx.tap.asDriver() .withLatestFrom(needUserName) { $1 } .flatMap { needUserName -> Driver<Bool> in guard needUserName else { return Driver.just(false) } return User.noNameAlert.rx.alert().asDriver(onErrorJustReturn: false) } tapFollowButton .filter { $0 }.map { _ in } .drive(ProfileViewController.present) .addDisposableTo(self.disposeBag) tapFollowButton .filter { !$0 } .withLatestFrom(viewModel.wish!) { $1 } .drive(viewModel.didWish!) .addDisposableTo(self.disposeBag) viewModel.wish? .drive(favoriteButton.rx.isSelected) .addDisposableTo(self.disposeBag) } } ...

Page 17: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

... private func configureLayout(by viewModel: CardViewModelType) { switch viewModel.cardType { case .big: self.configureLayoutForBig(by: viewModel) case .small: self.configureLayoutForSmall(by: viewModel) } } private func configureLayoutForBig(by viewModel: CardViewModelType) { // Construct Views self.addSubviews([self.coverImageView, ...]) ... // Layout Views self.coverImageView?.snp.makeConstraints { $0.size.equalTo(viewModel.cardType.coverImageSize) $0.top.equalToSuperview() $0.left.equalToSuperview() $0.right.equalToSuperview() } ... } private func configureLayoutForSmall(by viewModel: CardViewModelType) { ... } }

Page 18: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
Page 19: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

protocol CardViewConatinerType { var cardView: CardViewType? { get } func configure(with cardViewModel: CardViewModelType) }

class CardCollectionViewCell: UICollectionViewCell, CardViewContainerType { var cardView: CardViewType? { return self.contentView.subviews.first as? CardViewType }

func configure(with cardViewModel: CardViewModelType) { guard let cardView = self.cardView else { let _ = CardView(on: self.contentView, with: cardViewModel) // Initialize return } cardView.configure(by: cardViewModel) } override func prepareForReuse() { super.prepareForReuse() self.cardView?.coverImageView?.image = nil self.cardView?.profileImageButton?.setImage(nil, for: .normal) } }

Page 20: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

class CardTableViewCell: UITableViewCell, CardViewContainerType { var cardView: CardViewType? { return self.contentView.subviews.first as? CardViewType } func configure(with cardViewModel: CardViewModelType) { guard let cardView = self.cardView else { let cardView = CardView(on: self.contentView, with: cardViewModel, inset: Metric.cellInset) self.backgroundColor = UIColor.clear cardView.borderColor = UIColor.lightblue cardView.borderWidth = 1 return } cardView.configure(by: cardViewModel) } override func prepareForReuse() { super.prepareForReuse() self.cardView?.coverImageView?.image = nil self.cardView?.profileImageButton?.setImage(nil, for: .normal) } }

Page 21: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

let identifier = CardCollectionViewCell.className

let cell: CardCollectionViewCell = collectionView .dequeueReusableCell( withReuseIdentifier: identifier, for: indexPath ) as! CardCollectionViewCell

let viewModel = CardViewModel( cardType: item.cardType, data: item.data )

cell.configure(with: viewModel)

return cell

Page 22: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
Page 23: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
Page 24: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
Page 25: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

enum CardType { case small, big var cellSize: CGSize { switch self { case .small: return CGSize(width: 160, height: 200) case .big: return CGSize(width: 250, height: 230) } } }

Page 26: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

enum CardType { case small, big, realFinalISwearGodFinalType var cellSize: CGSize { switch self { case .small: return CGSize(width: 160, height: 200) case .big: return CGSize(width: 250, height: 230) case .realFinalISwearGodFinalType: return CGSize(width: 320, height: 100) } } }

Page 27: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

protocol CardViewModelType { var cardType: CardType { get } var title: String? { get } var subTitle: String? { get } var rating: Double? { get } var reviewCount: Int? { get } var profileImageButtonViewModel: ProfileImageButtonViewModelType? { get } var coverImageURLString: String? { get } var tags: [String]? { get } // Input var didWish: PublishSubject<Bool>? { get } // Output var wish: Driver<Bool>? { get } var disposeBag: DisposeBag { get } }

Page 28: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

protocol CardViewType { var coverImageView: UIImageView? { get } ... }

extension CardType: CardViewType { var coverImageView: UIImageView? { switch self { case .big: let imageView = UIImageView(frame: self.coverImageSize.rect) ... return imageView case .small: let imageView = UIImageView(frame: self.coverImageSize.rect) ... return imageView case .realFinalISwearGodFinalType: return nil } } ... }

Page 29: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017
Page 30: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

final class CardView: UIView, CardViewType { let coverImageView: UIImageView? ... private var disposeBag: DisposeBag required init(on superview: UIView, with viewModel: CardViewModelType, inset: UIEdgeInsets = .zero) { self.coverImageView = viewModel.cardType.coverImageView ... super.init(frame: viewModel.cardType.cellSize.rect)

superview.addSubview(self) self.snp.makeConstraints { $0.size.equalTo(viewModel.cardType.cellSize) $0.edges.equalTo(superview.snp.edges).inset(inset) }

self.configure(by: viewModel) self.configureLayout(by: viewModel) } ...

Page 31: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

func configure(by viewModel: CardViewModelType) { self.disposeBag = viewModel.disposeBag self.coverImageView?.setImage( with: viewModel.coverImageURLString, transformation: viewModel.cardType.coverImageSize.cloudinaryTransformation ) ...

self.favoriteButton?.removeTarget(self, action: nil, for: .allEvents) if let favoriteButton = self.favoriteButton { let needUserName = User.notification .map { $0.name?.isEmpty ?? true } let tapFollowButton = favoriteButton.rx.tap.asDriver() .withLatestFrom(needUserName) { $1 } .flatMap { needUserName -> Driver<Bool> in guard needUserName else { return Driver.just(false) } return User.noNameAlert.rx.alert().asDriver(onErrorJustReturn: false) } tapFollowButton .filter { $0 }.map { _ in } .drive(ProfileViewController.present) .addDisposableTo(self.disposeBag) tapFollowButton .filter { !$0 } .withLatestFrom(viewModel.wish!) { $1 } .drive(viewModel.didWish!) .addDisposableTo(self.disposeBag) viewModel.wish? .drive(favoriteButton.rx.isSelected) .addDisposableTo(self.disposeBag) } } ...

Page 32: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

... private func configureLayout(by viewModel: CardViewModelType) { switch viewModel.cardType { case .big: self.configureLayoutForBig(by: viewModel) case .small: self.configureLayoutForSmall(by: viewModel) case .realFinalISwearGodFinalType: self.configureLayoutForFinal(by: viewModel) } } private func configureLayoutForFinal(by viewModel: CardViewModelType) { ... } private func configureLayoutForBig(by viewModel: CardViewModelType) { ... } private func configureLayoutForSmall(by viewModel: CardViewModelType) { ... } }

Page 33: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

final class CardButton: UIView, CardViewContainerType { var cardView: CardViewType? { return self.subviews.first as? CardViewType }

func configure(with cardViewModel: CardViewModelType) { guard let cardView = self.cardView else { let cardView = CardView(on: self, with: cardViewModel) cardView.isUserInteractionEnabled = false return } cardView.configure(by: cardViewModel) } required init(cardViewModel: CardViewModelType) { super.init(frame: cardViewModel.cardType.cellSize.rect)) self.configure(with: cardViewModel) } }

Page 34: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017

let viewModel = CardViewModel(cardType: .realFinalISwearGodFinalType, data: $0) let button = CardButton(cardViewModel: viewModel) self.stackView.addArrangedSubview(button)

Page 35: 기획, 디자인 변경에 강한 카드뷰 만들기 - iOS Tech Talk 2017