diff --git a/iOS/Arirbnb/Arirbnb.xcodeproj/project.pbxproj b/iOS/Arirbnb/Arirbnb.xcodeproj/project.pbxproj index cf1c63fb6..df9fcd745 100644 --- a/iOS/Arirbnb/Arirbnb.xcodeproj/project.pbxproj +++ b/iOS/Arirbnb/Arirbnb.xcodeproj/project.pbxproj @@ -49,6 +49,9 @@ FFCA98CA2665CD360057ADDD /* SearchFlowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCA98C72665CD360057ADDD /* SearchFlowView.swift */; }; FFCA98CB2665CD360057ADDD /* FilteringCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = FFCA98C82665CD360057ADDD /* FilteringCell.xib */; }; FFCA98CD2665CD460057ADDD /* FilterItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCA98CC2665CD460057ADDD /* FilterItems.swift */; }; + FFCA98D02665DE0D0057ADDD /* DumbaSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCA98CF2665DE0D0057ADDD /* DumbaSlider.swift */; }; + FFCA98D22665DE2B0057ADDD /* SliderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCA98D12665DE2B0057ADDD /* SliderView.swift */; }; + FFCA98D42665E2570057ADDD /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFCA98D32665E2570057ADDD /* UIView+Extension.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -115,6 +118,9 @@ FFCA98C72665CD360057ADDD /* SearchFlowView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchFlowView.swift; sourceTree = ""; }; FFCA98C82665CD360057ADDD /* FilteringCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FilteringCell.xib; sourceTree = ""; }; FFCA98CC2665CD460057ADDD /* FilterItems.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilterItems.swift; sourceTree = ""; }; + FFCA98CF2665DE0D0057ADDD /* DumbaSlider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DumbaSlider.swift; sourceTree = ""; }; + FFCA98D12665DE2B0057ADDD /* SliderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SliderView.swift; sourceTree = ""; }; + FFCA98D32665E2570057ADDD /* UIView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Extension.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -374,6 +380,7 @@ FFCA98B52665CCCE0057ADDD /* View */ = { isa = PBXGroup; children = ( + FFCA98CE2665DE030057ADDD /* Slider */, FFCA98C62665CD360057ADDD /* FilteringCell.swift */, FFCA98C82665CD360057ADDD /* FilteringCell.xib */, FFCA98C72665CD360057ADDD /* SearchFlowView.swift */, @@ -400,10 +407,20 @@ FFCA98BF2665CD1F0057ADDD /* Day+Extension.swift */, FFCA98C02665CD1F0057ADDD /* NotificationName.swift */, FFCA98C12665CD1F0057ADDD /* UserInfoKey.swift */, + FFCA98D32665E2570057ADDD /* UIView+Extension.swift */, ); path = Extension; sourceTree = ""; }; + FFCA98CE2665DE030057ADDD /* Slider */ = { + isa = PBXGroup; + children = ( + FFCA98CF2665DE0D0057ADDD /* DumbaSlider.swift */, + FFCA98D12665DE2B0057ADDD /* SliderView.swift */, + ); + path = Slider; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -561,6 +578,7 @@ FFAB2ACD26620C4A008AEB31 /* ReuseIdentifierable.swift in Sources */, FF5767CF2653A2AE00F46A43 /* WishListViewController.swift in Sources */, FF665D1D26574E4200130ABB /* SearchResultCell.swift in Sources */, + FFCA98D22665DE2B0057ADDD /* SliderView.swift in Sources */, FF665D302657845700130ABB /* UIImageView+Extension.swift in Sources */, FF5767B42653311E00F46A43 /* ThemeDestinationsCell.swift in Sources */, FFCA98C52665CD1F0057ADDD /* UserInfoKey.swift in Sources */, @@ -569,7 +587,9 @@ FF5767672652490C00F46A43 /* MainSearchViewController.swift in Sources */, FFCA98CA2665CD360057ADDD /* SearchFlowView.swift in Sources */, FF5767632652490C00F46A43 /* AppDelegate.swift in Sources */, + FFCA98D42665E2570057ADDD /* UIView+Extension.swift in Sources */, FFCA98BB2665CCE70057ADDD /* DayLabel.swift in Sources */, + FFCA98D02665DE0D0057ADDD /* DumbaSlider.swift in Sources */, FFAB2AD126620E5F008AEB31 /* UINibCreateable.swift in Sources */, FFCA98B42665CCB90057ADDD /* SearchFilteringViewController.swift in Sources */, FF5767D52653A99400F46A43 /* MyReserVationViewModel.swift in Sources */, diff --git a/iOS/Arirbnb/Arirbnb/Extension/NotificationName.swift b/iOS/Arirbnb/Arirbnb/Extension/NotificationName.swift index 50720d279..220bea44f 100644 --- a/iOS/Arirbnb/Arirbnb/Extension/NotificationName.swift +++ b/iOS/Arirbnb/Arirbnb/Extension/NotificationName.swift @@ -10,4 +10,5 @@ import Foundation extension Notification.Name { static let selectDateDidChange = Notification.Name("selectDateDidChange") static let selectDateisChanging = Notification.Name("selectDateisChanging") + static let moveSearchFlowNextStep = Notification.Name("moveSearchFlowNextStep") } diff --git a/iOS/Arirbnb/Arirbnb/Extension/UIView+Extension.swift b/iOS/Arirbnb/Arirbnb/Extension/UIView+Extension.swift new file mode 100644 index 000000000..a2ffdc684 --- /dev/null +++ b/iOS/Arirbnb/Arirbnb/Extension/UIView+Extension.swift @@ -0,0 +1,17 @@ +// +// UIView+Extension.swift +// Arirbnb +// +// Created by 지북 on 2021/06/01. +// + +import UIKit + +extension UIView { + func configureFilteringViewLayout() { + self.heightAnchor.constraint(equalTo: superview?.heightAnchor ?? NSLayoutDimension(), multiplier: 0.725).isActive = true + } + + @objc func configure() { + } +} diff --git a/iOS/Arirbnb/Arirbnb/MainSearchScene/View/Cell/HeroImageCell.swift b/iOS/Arirbnb/Arirbnb/MainSearchScene/View/Cell/HeroImageCell.swift index 5050f30d8..db3b3bdc2 100644 --- a/iOS/Arirbnb/Arirbnb/MainSearchScene/View/Cell/HeroImageCell.swift +++ b/iOS/Arirbnb/Arirbnb/MainSearchScene/View/Cell/HeroImageCell.swift @@ -20,7 +20,7 @@ class HeroImageCell: UICollectionViewCell, ReuseIdentifierable { configure() } - func configure() { + @objc override func configure() { contentView.addSubview(heroImageView) heroImageView.translatesAutoresizingMaskIntoConstraints = false diff --git a/iOS/Arirbnb/Arirbnb/SearchFilteringScene/SearchFilteringViewController.swift b/iOS/Arirbnb/Arirbnb/SearchFilteringScene/SearchFilteringViewController.swift index 9b37a6868..75bd516cf 100644 --- a/iOS/Arirbnb/Arirbnb/SearchFilteringScene/SearchFilteringViewController.swift +++ b/iOS/Arirbnb/Arirbnb/SearchFilteringScene/SearchFilteringViewController.swift @@ -31,18 +31,21 @@ class SearchFilteringViewController: UIViewController, ViewControllerIdentifiera } private lazy var filteringStackView = UIStackView() + private var filteringViews: [UIView] = [] private lazy var calendar = DumbaCalendar() + private lazy var sliderView = SliderView() private lazy var filteringTableView = UITableView() private lazy var flowView = SearchFlowView() + private var nowFilteringStep: Int = 0 private var destination: Destination? private var filterItems: FilterItems? override func viewDidLoad() { super.viewDidLoad() + filteringViews = [calendar, sliderView] configureStackView() addSubViews() - configureCalendar() configureTableView() configureFilterItems() addObservers() @@ -56,9 +59,7 @@ class SearchFilteringViewController: UIViewController, ViewControllerIdentifiera filteringStackView.distribution = .fill configureStackViewLayout() } - private func configureCalendar() { - calendar.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.725).isActive = true - } + private func configureTableView() { filteringTableView.translatesAutoresizingMaskIntoConstraints = false @@ -81,10 +82,12 @@ class SearchFilteringViewController: UIViewController, ViewControllerIdentifiera private func addObservers() { NotificationCenter.default.addObserver(self, selector: #selector(setDateChange(_:)), name: .selectDateDidChange, object: calendar) NotificationCenter.default.addObserver(self, selector: #selector(setDateIsChanging(_:)), name: .selectDateisChanging, object: calendar) + NotificationCenter.default.addObserver(self, selector: #selector(nextButtonDidTap(_:)), name: .moveSearchFlowNextStep, object: flowView) } private func addSubViews() { - filteringStackView.addArrangedSubview(calendar) + filteringStackView.addArrangedSubview(filteringViews[nowFilteringStep]) + filteringViews[nowFilteringStep].configureFilteringViewLayout() filteringStackView.addArrangedSubview(filteringTableView) filteringStackView.addArrangedSubview(flowView) } @@ -118,6 +121,14 @@ extension SearchFilteringViewController { flowView.doNotMeetTheConditions() } + + @objc func nextButtonDidTap(_ notification: Notification) { + filteringViews[nowFilteringStep].removeFromSuperview() + nowFilteringStep += 1 + filteringStackView.insertArrangedSubview(filteringViews[nowFilteringStep], at: 0) + filteringViews[nowFilteringStep].configureFilteringViewLayout() + filteringViews[nowFilteringStep].configure() + } } //MARK: - Data Source diff --git a/iOS/Arirbnb/Arirbnb/SearchFilteringScene/View/SearchFlowView.swift b/iOS/Arirbnb/Arirbnb/SearchFilteringScene/View/SearchFlowView.swift index 55ebdc325..073c3745f 100644 --- a/iOS/Arirbnb/Arirbnb/SearchFilteringScene/View/SearchFlowView.swift +++ b/iOS/Arirbnb/Arirbnb/SearchFilteringScene/View/SearchFlowView.swift @@ -24,7 +24,7 @@ class SearchFlowView: UIView { configure() } - private func configure() { + @objc override func configure() { skipButton.setTitle("건너뛰기", for: .normal) skipButton.setTitleColor(.black, for: .normal) @@ -39,6 +39,8 @@ class SearchFlowView: UIView { addSubview(nextButton) configureDefaultLayout() + + nextButton.addTarget(self, action: #selector(nextButtonDidTap(_:)), for: .touchUpInside) } private func configureDefaultLayout() { @@ -92,4 +94,8 @@ class SearchFlowView: UIView { eraseButton.removeFromSuperview() addSkipButton() } + + @objc func nextButtonDidTap(_ sendor: UIButton) { + NotificationCenter.default.post(name: .moveSearchFlowNextStep, object: self) + } } diff --git a/iOS/Arirbnb/Arirbnb/SearchFilteringScene/View/Slider/DumbaSlider.swift b/iOS/Arirbnb/Arirbnb/SearchFilteringScene/View/Slider/DumbaSlider.swift new file mode 100644 index 000000000..063f1c0be --- /dev/null +++ b/iOS/Arirbnb/Arirbnb/SearchFilteringScene/View/Slider/DumbaSlider.swift @@ -0,0 +1,160 @@ +// +// DumbaSlider.swift +// Arirbnb +// +// Created by 지북 on 2021/05/29. +// + +import UIKit + +class DumbaSlider: UIControl { + var minimumValue: CGFloat = 0 + var maximumValue: CGFloat = 1 + var lowerValue: CGFloat = 0.2 + var upperValue: CGFloat = 0.8 + + var thumbImage = #imageLiteral(resourceName: "pause") + + + + var trackTintColor = UIColor(white: 0.9, alpha: 1) + var trackHighlightTintColor = #colorLiteral(red: 0.9098039216, green: 0.2980392157, blue: 0.3764705882, alpha: 1) + + private let lowerThumbImageView = UIImageView() + private let upperThumbImageView = UIImageView() + private var previousLocation = CGPoint() + private let trackLayer = RangeSliderTrackLayer() + + override var frame: CGRect { + didSet { + updateLayerFrames() + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + configure() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + configure() + } + + @objc override func configure() { + + trackLayer.rangeSlider = self + trackLayer.contentsScale = UIScreen.main.scale + layer.addSublayer(trackLayer) + + lowerThumbImageView.image = thumbImage + addSubview(lowerThumbImageView) + + upperThumbImageView.image = thumbImage + addSubview(upperThumbImageView) + + } + + private func updateLayerFrames() { + trackLayer.frame = bounds.insetBy(dx: 0.0, dy: bounds.height / 3) + trackLayer.setNeedsDisplay() + lowerThumbImageView.frame = CGRect(origin: thumbOriginForValue(lowerValue), + size: thumbImage.size) + upperThumbImageView.frame = CGRect(origin: thumbOriginForValue(upperValue), + size: thumbImage.size) + } + + func positionForValue(_ value: CGFloat) -> CGFloat { + return bounds.width * value + } + + private func thumbOriginForValue(_ value: CGFloat) -> CGPoint { + let x = positionForValue(value) - thumbImage.size.width / 2.0 + return CGPoint(x: x, y: (bounds.height - thumbImage.size.height) / 2.0) + } +} + +extension DumbaSlider { + override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { + // 1 + previousLocation = touch.location(in: self) + + // 2 + if lowerThumbImageView.frame.contains(previousLocation) { + lowerThumbImageView.isHighlighted = true + } else if upperThumbImageView.frame.contains(previousLocation) { + upperThumbImageView.isHighlighted = true + } + + // 3 + return lowerThumbImageView.isHighlighted || upperThumbImageView.isHighlighted + } + + override func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { + let location = touch.location(in: self) + + // 1 + let deltaLocation = location.x - previousLocation.x + let deltaValue = (maximumValue - minimumValue) * deltaLocation / bounds.width + + previousLocation = location + + // 2 + if lowerThumbImageView.isHighlighted { + lowerValue += deltaValue + lowerValue = boundValue(lowerValue, toLowerValue: minimumValue, + upperValue: upperValue) + } else if upperThumbImageView.isHighlighted { + upperValue += deltaValue + upperValue = boundValue(upperValue, toLowerValue: lowerValue, + upperValue: maximumValue) + } + + // 3 + CATransaction.begin() + CATransaction.setDisableActions(true) + + updateLayerFrames() + + CATransaction.commit() + + return true + } + + // 4 + private func boundValue(_ value: CGFloat, toLowerValue lowerValue: CGFloat, + upperValue: CGFloat) -> CGFloat { + return min(max(value, lowerValue), upperValue) + } + + override func endTracking(_ touch: UITouch?, with event: UIEvent?) { + lowerThumbImageView.isHighlighted = false + upperThumbImageView.isHighlighted = false + } +} + +class RangeSliderTrackLayer: CALayer { + weak var rangeSlider: DumbaSlider? + + override func draw(in ctx: CGContext) { + guard let slider = rangeSlider else { + return + } + + let path = UIBezierPath(roundedRect: bounds, cornerRadius: 10) + ctx.addPath(path.cgPath) + + ctx.setFillColor(slider.trackTintColor.cgColor) + ctx.fillPath() + + ctx.setFillColor(slider.trackHighlightTintColor.cgColor) + let lowerValuePosition = slider.positionForValue(slider.lowerValue) + let upperValuePosition = slider.positionForValue(slider.upperValue) + let rect = CGRect(x: lowerValuePosition, y: 0, + width: upperValuePosition - lowerValuePosition, + height: bounds.height) + ctx.fill(rect) + } +} + + diff --git a/iOS/Arirbnb/Arirbnb/SearchFilteringScene/View/Slider/SliderView.swift b/iOS/Arirbnb/Arirbnb/SearchFilteringScene/View/Slider/SliderView.swift new file mode 100644 index 000000000..224785c71 --- /dev/null +++ b/iOS/Arirbnb/Arirbnb/SearchFilteringScene/View/Slider/SliderView.swift @@ -0,0 +1,42 @@ +// +// SliderView.swift +// Arirbnb +// +// Created by 지북 on 2021/06/01. +// + +import UIKit + +class SliderView: UIView { + + private lazy var priceHeaderLabel = UILabel() + private lazy var slider = DumbaSlider() + + override init(frame: CGRect) { + super.init(frame: frame) + configure() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + configure() + } + + @objc override func configure() { + slider.translatesAutoresizingMaskIntoConstraints = false + priceHeaderLabel.text = "가격 범위" + priceHeaderLabel.adjustsFontForContentSizeCategory = true + priceHeaderLabel.font = UIFont.preferredFont(forTextStyle: .headline) + + addSubview(slider) + addSubview(priceHeaderLabel) + + + let margin: CGFloat = 20 + let width = (superview?.bounds.width ?? 0) - 2 * margin + let height: CGFloat = 30 + + slider.frame = CGRect(x: 0, y: 0, width: width, height: height) + slider.center = superview?.center ?? CGPoint.zero + } +} diff --git a/iOS/Arirbnb/Arirbnb/SupportingFiles/Assets.xcassets/pause.imageset/Contents.json b/iOS/Arirbnb/Arirbnb/SupportingFiles/Assets.xcassets/pause.imageset/Contents.json new file mode 100644 index 000000000..70995de52 --- /dev/null +++ b/iOS/Arirbnb/Arirbnb/SupportingFiles/Assets.xcassets/pause.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "pause (2).png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iOS/Arirbnb/Arirbnb/SupportingFiles/Assets.xcassets/pause.imageset/pause (2).png b/iOS/Arirbnb/Arirbnb/SupportingFiles/Assets.xcassets/pause.imageset/pause (2).png new file mode 100644 index 000000000..9d78bcde4 Binary files /dev/null and b/iOS/Arirbnb/Arirbnb/SupportingFiles/Assets.xcassets/pause.imageset/pause (2).png differ