2021. 8. 23. 22:42ใiOS/View
์ฝ๋์คํ์ด ๋ฉํ ๋ง์ผ๋ก ์งํํ๋ Bottom Sheet ๊ตฌํ์ ๊ธฐ๋ก์ผ๋ก ๋จ๊ฒจ๋ก๋๋ค.
์ด๊ฑธ ์ ํํ Bottom Sheet์ด๋ผ๊ณ ๋ถ๋ฅด๋์ง, ๋ชจ๋ฌ์ด๋ผ๊ณ ๋ถ๋ฌ์ผํ ์ง ์กฐ๊ธ ์ ๋งคํ ๋ถ๋ถ์ด ์์ง๋ง,
์ด ํฌ์คํธ์์ ๊ถ๊ทน์ ์ผ๋ก ๋ณด์ฌ๋๋ฆฌ๋ ค๊ณ ํ๋๊ฑด ์ด๋ฐ ๋ถ๋ถ์ ๋๋ค.
์ฐ์ ์ ๊ฐ ์ฐธ๊ณ ํ ํ๋ก์ ํธ๋ ์๋์ ๊ฐ์ต๋๋ค.
https://github.com/LucaIaco/SwipeableView
ํด๋น ํ๋ก์ ํธ๋ฅผ Stack Overflow์์ ๋ฐ๊ฒฌํ๊ณ ์ง์ ๋ค์ด๋ฐ์์ ์คํ์์ผ๋ณด๊ณ ์ฝ๋๋ฅผ ์ด๋์ ๋ ๋๋ฌ๋ณด๋,
๊ถ๊ทน์ ์ผ๋ก '์๋ก์ด ํ๋กํ ์ฝ'์ ๋ง๋ค์ด ๋์ จ๋๋ผ๊ณ ์.
ํด๋น ํ๋กํ ์ฝ ํ์ผ์ ๋ฐ์์ค์ ์ ๋ฐ๋ก ํด์ํ๋ฉด์ ์ ์ฉํ ์ ์๋ ๋ฅ๋ ฅ์ด ๋์ ๋ค๋ฉด ๊ทธ๋ ๊ฒ ํ์๋ฉด ๋๊ฒ ์ง๋ง...
์กฐ๊ธ ์ด๋ ค์ฐ์๋ค๋ฉด ์ฒจ๋ถํ ๋งํฌ์ ๋ ํ์งํ ๋ฆฌ์์ ํ๋ก์ ํธ๋ฅผ ๋ค์ด ๋ฐ์ผ์๊ณ
์ง์ ์ฝ๋์ ๋ธ๋ ์ดํฌ ํฌ์ธํธ๋ฅผ ๊ฑธ์ด๋ณด๋ฉด์ ์๋ฎฌ๋ ์ดํฐ๋ก ์ด๋์ ๋ ๋ง์ ธ๋ณด๊ณ
์ด๋ค ์ํฉ์ ์ด๋ค ํจ์๊ฐ ํธ์ถ๋๊ณ ํด๋น ํ๋กํ ์ฝ์ด ์ด๋ป๊ฒ ์๋ํ๋์ง ์ง์ ๋์ผ๋ก ํ์ธํ์๋๊ฒ
ํ์ํ ๋ถ๋ถ์ ์ฐพ์์ ์ง์ ๊ตฌํํ๋๋ฐ ๋์์ด ๋ ๊ฒ ๊ฐ์ต๋๋ค.
๊ทธ๋ผ ์ด์ ์ง์ ๊ตฌํํ ๊ณผ์ ๊ณผ ์ฝ๋๋ฅผ ๊ฐ๋ตํ๊ฒ ๋ณด์ฌ๋๋ฆฌ๊ฒ ์ต๋๋ค.
์ค๋ ์ ๊ฐ ๊ตฌํํ๊ณ ์ ํ๋ ๊ฒ์, 'map picker'๋ผ๋ ๋ฒํผ์ ๋๋ฅด๋ฉด ์๋์์ ๋ชจ๋ฌ์ด ์ฌ๋ผ์ค๊ณ
๊ทธ ๋ชจ๋ฌ์ ์ ์๋๋ก ํฌ๊ธฐ๋ฅผ ๋๋ฆฌ๊ฑฐ๋ ์ค์ผ ์ ์๊ณ ,
๊ทธ ๋ชจ๋ฌ์ด ์์ง์ผ๋ 'map picker'๋ฒํผ ๋ํ ๊ฐ๊ฒฉ์ ๋ง๊ฒ ์์ง์ฌ์ฃผ๋๊ฒ๋๋ค.
0. ํด๋น ๋ ํ์งํ ๋ฆฌ์์ ํ๋ก์ ํธ ๋ค์ด ๋ฐ์ ๋ค
๋ ๊ฐ์ ํ๋กํ ์ฝ์ ์์ ์ ํ๋ก์ ํธ ํ์ผ์ ํฌํจํ๊ธฐ
ํ์ผ์ ๋ฃ์ด์ค ๋ค์ ํ๋กํ ์ฝ์ ๋ถ๋ฌ์์ค๋๋ค.
class ViewController: UIViewController, SwipeableViewProtocol {
func swipeableViewDidExpand(swipeableView: SwipeableView, previousState: Bool) {
print(2)
}
func swipeableViewDidCollapse(swipeableView: SwipeableView, previousState: Bool) {
print(3)
}
func swipeableViewDidPan(swipeableView: SwipeableView, percentage: CGFloat) {
print(1)
}
ํจ์ ์ด๋ฆ์์ ์ ์ ์๋ฏ์ด expand ํ์๋, collapseํ์๋, pan ๋์์๋ ๋ถ๋ฌ์ง๋ ํจ์์ ๋๋ค.
ํด๋น ํ๋ก์ ํธ๋ฅผ ์ ์ํ์ ๋ถ์ ํด๋น ํจ์๋ค์ด ๋ถ๋ฌ์ง๋๋ง๋ค ์ํธ์์ฉ์ ๋ง๋ค๊ณ ์ถ์ผ์ จ๋ ๊ฒ ๊ฐ์ต๋๋ค.
๊ทธ๋ฌ๋ ์ ๋ ๋ฑํ ๋ฐ์ดํฐ๋ฅผ ๋๊ฒจ์ค ํ์๋ ์๊ณ ๋ณ๊ฒฝ ์ฌํญ์ด ์์ด์ ๋จ์ print๋ฌธ์ผ๋ก ๋์ฒดํ์ต๋๋ค.
1. Swipe View๋ผ๋ ๋ทฐ๋ฅผ ๋ทฐ ์์ ๋ฃ๊ธฐ & constraint ์ ์ํ๊ธฐ
์ Swipe View์ ๋ชจ๋ฌ ๋ทฐ๋ฅผ ์ฐ๊ฒฐํ ๊ฑด๋ฐ์,
์ ๋ทฐ๊ฐ ์์ง์ฌ์ผ ํ๊ธฐ ๋๋ฌธ์ constraint๊ฐ ์์ ์์ฌ๋ก ๋ฐ๋์ด์ผ ํฉ๋๋ค.
์ฌ๊ธฐ์ ์ ๊ฐ ์ฒจ๋ถํ ๋ ํ์งํ ๋ฆฌ์์ ์ง์ ํ๋ก์ ํธ๋ฅผ ๋ค์ด ๋ฐ๊ณ ๋ง์ ธ๋ณด์ ๋ถ๋ค์ ๋์น์ฑ๊ฒ ์ง๋ง,
ํน์ดํ๊ฒ๋ ์ 'Swipe View'์ ์ constraint(Flex Layout)๋ฅผ var๋ก ์ง์ ํด์ค๋๋ค.
(์ ๋ ์ฐธ๊ณ ํ ํ๋ก์ ํธ์ ๋ค๋ฅด๊ฒ 'map picker'๋ผ๋ ๋ฒํผ์ ๊ธฐ์ค์ผ๋ก ์ผ์์ต๋๋ค.)
2. Swipe View ์ฝ๋ ์ง๊ธฐ
2-1. ์ฒ์ ์ํ
์ ํฌ๋ ๋ฒํผ์ ๋๋ฅด๊ธฐ ์ ์๋ Swipe View๊ฐ ๋ณด์ด์ง ์๋ ์ํ์ฌ์ผ ํฉ๋๋ค.
๊ทธ๊ฑธ ๊ณ ๋ คํด์ ViewDidLoad์์๋ ๋ณด์ด์ง ์๋๋ก ์ค์ ํฉ๋๋ค.
@IBOutlet weak var swipeView: SwipeableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.swipeView.isHidden = true
self.swipeView.isUserInteractionEnabled = false
self.swipeView.delegate = self
}
์คํํด๋ณด๋ฉด ๊ทธ๋ฅ ํ๋ฒํ ํ๋์ ๋ทฐ๊ฐ ๋ํ๋ฉ๋๋ค.
๋น์ฐํฉ๋๋ค! Hidden์ true๋ก ์ค์ ํด๋์์ผ๋๊น์.
2-2. ๋ฒํผ์ ๋๋ ์ ๋(๋ชจ๋ฌ๋ทฐ ์ค์ )
๊ทธ๋ผ ์ด์ ๋ง์ฝ ๋ฒํผ์ ๋๋ ์๋ ์ค์ ํ ๊ฒ๋ค์ ํจ์๋ก ๋ฐ๋ก ๋ง๋ค์ด ์ค๋๋ค.
func childViewSettings() {
self.swipeView.isHidden = false
self.swipeView.isUserInteractionEnabled = true
self.swipeView.flexibleLayout = .init(with: self.flexLayout, end: 40.0)
//indicator ์ฌ๋ถ
self.swipeView.isSwipeIndicatorVisible = false
//๋ฅ๊ทผ ๋ชจ์๋ฆฌ ์ฌ๋ถ
self.swipeView.hasRoundedCorners = true
//์์๋๋ ํด๋๋ ๋ ๋ค child View์ interaction ๊ฐ๋ฅ
self.swipeView.childViewInteractionOnExpandedOnly = false
}
์ฌ๊ธฐ์ flexibleLayout์ด๋ผ๋ ๊ฒ ๋ณด์ด์ฃ ?
์ด๊ฑด QuickHelp๋ฑ์ผ๋ก ํ์ธํด๋ณด๋ฉด Declared In 'SwipeableView.swift'๋ผ๋ ์ค๋ช ์ ๋ณผ ์ ์์ต๋๋ค.
์ฆ, ํ๋ก์ ํธ ์์ฑ์ ๋ถ์ด ๋ง๋ค์ด ๋ ํ๋กํ ์ฝ์ ํฌํจ๋๋ ํจ์์ ๋๋ค.
์๋ ๋ฐฉ์์ ๋ณด์ํ๋ .init(with: (constraint ๋ฃ์ด์ฃผ๊ธฐ), end: (์ซ์))๋ค์.
์ ์ซ์๋ ์ง์ !! ํ ์คํธ ํด๋ณด๋ฉด ๊ธ๋ฐฉ ๋ฐ๊ฒฌํ ์ ์๋๋ฐ์, constraint ์ ์ฉ ๋ฒ์์ ๋๋ค.
์ ๋ 40์ผ๋ก ์ฃผ์์ต๋๋ค.(์ง์ ๊ตฌํํด๋ณด๊ณ ๊ฐ์ฅ ์ ํฉํ๋ค๊ณ ์๊ฐ๋๋ ์ซ์๋ฅผ ๋ฃ์ด์ฃผ์ธ์)
constraint๋ ์๊น ์ ํฌ๊ฐ ์์ ๋ง๋ค์ด์ค flexLayout์ด๊ฒ ์ฃ ?
3. ๋ฒํผ ๋๋ ์ ๋ SwipeView ๋ํ๋๊ฒ ํ๊ธฐ
์ด์ SwipeView๋ฅผ ๋ํ๋๊ฒ ํ๊ณ , ํด๋น View์์ ๋ณด์ฌ์ฃผ๊ณ ์ถ์(๊ตฌํํ๊ณ ์ถ์)
๋ทฐ๋ฅผ ์ฐ๊ฒฐํด์ค๊ฒ๋๋ค.
์ ๋ ์ด๋ฐ์์ผ๋ก ์์ฃผ ๊ฐ๋จํ๊ฒ ๊ตฌํํด๋์์ต๋๋ค.
Storyboard ID๋ฅผ "childVC"๋ผ๊ณ ๋์์ต๋๋ค.
childVC์ ๋ทฐ์ปจํธ๋กค๋ฌ ์ฝ๋๋ ๊ฐ๋จํฉ๋๋ค.
class ChildViewController: UIViewController{
weak var swipeView:SwipeableView? //์ค์
override func viewDidLoad() {
super.viewDidLoad()
}
ํ์ํ ํ ์ด๋ธ๋ทฐ๋.. ๋ฒํผ์ด ์์ผ๋ฉด ์ถ๊ฐ์ ์ผ๋ก ์ฐ๊ฒฐํด์ฃผ๋ฉด ๋๊ฒ ์ฃ ?
๊ทธ๋ผ ์ด์ ๋ค์ ์๋ ๋ทฐ์ปจํธ๋กค๋ฌ ์ฝ๋๋ก ๋์์ค๊ฒ ์ต๋๋ค.
map picker๋ผ๋ ๋ฒํผ์ ๋๋ ์๋ ์คํ๋๋ ํจ์์์ childVC๋ฅผ ๋ถ๋ฌ์์ค๊ฒ๋๋ค.
@IBAction func pickerSelected(_ sender: Any) {
//childViewController์ฐ๊ฒฐ
if let childViewController = self.storyboard?.instantiateViewController(withIdentifier:"childVC") as? ChildViewController {
childViewSettings()
// alternative way to interact with the swipeable view from within a child view
childViewController.swipeView = self.swipeView
// plug the child view into the swipeable view
self.swipeView.setChildView(childVC: childViewController, parentVC: self)
}
}
์ง์ ํ ์คํธ๋ฅผ ํด๋ณด๋ if๋ฌธ์ ๊ฑธ์ด์ฃผ์ง ์์ผ๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํ๋๋ผ๊ณ ์.
๊ทธ๋์ if๋ฌธ์ ๊ฑธ๊ณ childViewController์ ์ฐ๋ฆฌ๊ฐ ๋ณด์ฌ์ฃผ๊ณ ์ถ์ "childVC"๋ฅผ ์ ์ฅํด์ค๋๋ค.
๊ทธ๋ฆฌ๊ณ childViewSettings()ํจ์(๋ฐ๋ก ์์์ ๋ง๋ค์ด์ค ํจ์)๋ฅผ ๋ถ๋ฌ์์ฃผ๊ฒ ์ต๋๋ค.
๋ค์ ๋ ์ค์ ํด๋น ํ๋กํ ์ฝ์ ๋ง๋์ ๋ถ์ ํํ ๋ฆฌ์ผ๋๋ก ๋ฐ๋ผ๊ฐ์ต๋๋ค.
(์ ์ด์ ์กด์ฌํ๋ ํจ์๋ค์ด ์๋! ๊ฐ์กฐ)
4. map picker ๋ฒํผ๋ ํจ๊ป ์์ง์ด๊ฒ ํ๊ธฐ
์ 3๋ฒ๊น์ง ํ๊ณ ์คํ์ ํด ๋ณด๋ฉด ์ด์ ๋ชจ๋ฌ์ด ์ ์๊ธธ ๊ฒ์ด๊ณ , ์์ง์์๋ ๋ฌธ์ ๊ฐ ์๊ฒ ์ง๋ง
๋ฒํผ์ด ํจ๊ป ์์ง์ด์ง ์๋๋ค๋๊ฑธ ๋ฐ๊ฒฌํ์ ๊ฒ๋๋ค.
๊ทธ๋์ SwipeableItem ํ๋กํ ์ฝ์ ์ด์ฉํด์ค๊ฒ๋๋ค.
@IBOutlet weak var pickerFlexLayout: NSLayoutConstraint!
@IBOutlet weak var picker: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
.
.
.
//addAnimateableItem์ layout์ ๋ฃ๊ณ end ๊ฐ์ ์กฐ์ ํ๋ฉด์ ์์ง์ด๋๊ฑฐ ํ์ธ
self.swipeView.addAnimatableItem(SwipeableItemLayout(with: pickerFlexLayout, end: 100.0))
}
์์์ ํ ๊ฒ๊ณผ ์ ์ฌํ๊ฒ constraint๋ฅผ ์ ์ํด์ฃผ๊ณ
ํ๋กํ ์ฝ์์ ํ๋ผ๋๋๋ก ํด์ฃผ๋ฉด ๋ชจ๋ ์๋ฃ๋์์ต๋๋ค.
์ด๋ ๊ฒ ๊ฐ๋จํ๊ฒ ๋ฒํผ์ด ํจ๊ป ์์ง์ด๋ ๋ชจ๋ฌ๋ทฐ bottom sheet๊ฐ ์์ฑ๋์์ต๋๋ค!!
์์ ๋ง์๋๋ ธ์ง๋ง ์ง์ !! ํด๋น ๋ ํ์งํ ๋ฆฌ์์ ํ๋ก์ ํธ๋ฅผ ๋ค์ด๋ฐ์ ํ ์คํธ ํด๋ณด๊ณ
์ ๋ธ๋ก๊ทธ๋ฅผ ์ฐธ๊ณ ํ์๋ฉด์ ๊ตฌํํ์๋ ๊ฑธ ์ถ์ฒ๋๋ฆฝ๋๋ค.
(+)
cocoapod์ผ๋ก ์ค์นํ๋ ๋จ์ํ Bottom Sheet๋ ๊ตฌํํด๋ณด์๋๋ฐ,
์คํ๋ ค ํ๋กํ ์ฝ์ ์ด์ฉํ ๋ณต์กํ ์ฝ๋๊ฐ ์ข ๋ ์ปค์คํฐ๋ง์ด์งํ๊ธฐ ์ฝ๊ณ ์ ์๊ฒ ์ ๋ง์๋ ๊ฒ ๊ฐ์ต๋๋ค.