๐ผ ImageSlideshow
ImageSlideshow ์ค์น, ๋ทฐ ์์ฑํ๊ธฐ, ์ด๋ฏธ์ง ๋ฑ๋กํ๋ ๋ฒ์ ์ด์ ํฌ์คํ ์ ์ฐธ๊ณ ํด์ฃผ์ธ์. ํด๋น ํฌ์คํ ์์๋ Label Page Indicator ์ ์ฉํ๋ ๋ฒ, ์ด๋ฏธ์ง ํด๋ฆญ์ ์ ์ฒด ํ๋ฉด์ผ๋ก ์ ํํ๋ ๋ฒ์ ๋ํด ๋ค๋ค๋ณด๊ฒ ์ต๋๋ค.
[iOS/Swift] Image Slide show + Firebase Storage ๋ก ์ฌ๋ผ์ด๋ ์ด๋ฏธ์ง๋ทฐ ๊ตฌํํ๊ธฐ - 1
๐ผ ImageSlideshow Customizable Swift image slideshow with circular scrolling, timer and full screen viewer Image Slide show ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ฌ๋ฌ ์ด๋ฏธ์ง๋ฅผ ์์ผ๋ก ์ฌ๋ผ์ด๋ํ๋ UI ๋ฅผ ๊ตฌํํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ..
jellysong.tistory.com
3. Custom Label Page Indicator ์ ์ฉํ๊ธฐ
๊ธฐ๋ณธ์ผ๋ก ์ ๊ณต๋๋ Label Page Indicator ๋ฅผ ์ด์ฉํ ๊ฒฝ์ฐ, ๊ธฐ์กด ์ฝ๋์์ ๋ค์ ํ ์ค์ ์ถ๊ฐํ๋ฉด ๋ฉ๋๋ค.
slideshow.pageIndicator = LabelPageIndicator()
Github ๋ฌธ์๋, ์ ๋๋ฆฌ๋ ์ ํฌ๋ธ๋ Label Page Indicator ๋ฅผ ๋๋ฑ ์ ์ฉํ์ จ๋๋ฐ์. ์ ๋ ์ด๋ฏธ์ง ์ฌ์ด์ฆ๊ฐ ์์์ ๊ทธ๋ฐ์ง width ์กฐ์ ์ด ์ ์์ ์ผ๋ก ๋์ง ์์ 1/... ์ฒ๋ผ ์๋ ค์ ๋ํ๋ฌ์ต๋๋ค. ๐ฅฒ Label ์ SubView ๋ก ์ ์ฉํ๋ ๋ฐฉ๋ฒ๋ ํด๋ดค๋๋ฐ, ์คํฌ๋กค์ ๋งค๋๋ฝ์ง ์๋๋ผ๊ณ ์. ๊ณ ๋ฏผํ๋ค๊ฐ extension ์ ํตํด LabelPageIndicator ์ ํฐํธ์ฌ์ด์ฆ์ width ๋ฅผ ์ปค์คํ ํ๊ฒ ์ง์ ํด์คฌ์ต๋๋ค.
You can also use your own page indicator by adopting the PageIndicatorView protocol.
import Foundation
import ImageSlideshow
extension LabelPageIndicator {
public func setCustomLabel() {
self.textColor = .white
let systemFont = UIFont.systemFont(ofSize: 12.0)
self.attributedText = NSAttributedString(string: self.text ?? "",
attributes: [NSAttributedString.Key.font : systemFont])
}
public override func sizeToFit() {
let maximumString = String(repeating: "16", count: numberOfPages) as NSString
self.frame.size = maximumString.size(withAttributes: [.font: font as Any])
setCustomLabel()
}
}
์ด๋ฒ์๋ TableView Cell ์์ ImageSlideshow ๋ฅผ ์ด์ฉํ๊ณ , Cell ์์ LabelPageIndicator ์ค์ ์ ํด์ฃผ์์ต๋๋ค. Cell ์ ๊ธฐ๋ณธ UI ์ ๊ด๋ จ๋ ๋์์ด๋ผ ์๊ฐํด์ Cell Class ์์ ์ ์ฉ์ ํ์ต๋๋ค.
class ReviewCell: UITableViewCell {
//...
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code ...
reviewImageSlide.setCornerRadius()
let labelPageIndicator = LabelPageIndicator()
reviewImageSlide.pageIndicator = labelPageIndicator
reviewImageSlide.pageIndicatorPosition = .init(horizontal: .right(padding: 10),
vertical: .customBottom(padding: 10))
}
}
์ด๋ฏธ์ง๋ Cell ๋ง๋ค ๋์ ์ผ๋ก ๋ณํ๊ธฐ ๋๋ฌธ์ TableViewDatasource ๋ด์์ ์ ์ฉํ์ต๋๋ค.
// MARK: TableView - Datasource
extension ReviewTableViewController: UITableViewDataSource {
// ...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// dequeueReusableCell ...
let imageInputs = FirebaseStorage.getImageInputs(images: images)
cell.reviewImageSlide.setImageInputs(imageInputs)
cell.reviewImageSlide.contentScaleMode = .scaleAspectFill
}
}
์ฌ๊ธฐ๊น์ง ์ ์๋๋๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ค๋ฅธ์ชฝ ํ๋จ์ Label Page Indicator ๊ฐ ๋ํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค! ํด๋น ์ฌ์ง์ ๊ฐ๋ฐ์ค์ธ ์ดํ๊ณผ ๊ด๋ จ์ด ์์ต๋๋ค.
4. Full Screen view ์ ํํ๊ธฐ + Label Page Indicator ์ ์ฉํ๊ธฐ
๊ฐ๋ฐํ๋ ์ ๋๋ฆฌ๋ ์ ํฌ๋ธ๋ฅผ ์ฐธ๊ณ ํ ๋ด์ฉ์ ๋๋ค.
ImageSlideshow ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ด๋ฏธ์ง๋ง ๋ํ๋๋ ์ ์ฒดํ๋ฉด์ ์ ๊ณตํ๊ณ Pinch Zoom ์ ํตํด ํ๋๊ฐ ๊ฐ๋ฅํฉ๋๋ค. ์ง์ ๊ฐ๋ฐํด์ผํ๋ ๋ถ๋ถ์ ์ด๋ฏธ์ง๋ฅผ ํฐ์นํ์ ๋ ์ ์ฒดํ๋ฉด์ด ๋ํ๋๋๋ก ํ๋ ๋ถ๋ถ์ ๋๋ค.
์ด๋ฏธ์ง๋ฅผ ํฐ์นํ๋ ๊ฒ์ด๋๊น UITapGestureRecognizer ๋ฅผ ์ด์ฉํ๋ฉด ๋๊ฒ ์ง์?! Tap Gesture ๋ํ UI ์ค์ ์ ๊ด๋ จ๋๊ฒ์ด๋ผ ์๊ฐํด์ Cell ๋ด๋ถ์์ ์ค์ ํ์ต๋๋ค. ์ด๋ฏธ์ง๋ฅผ ํญ ํ์๋, didTapImageSlide ์ก์ ํจ์๊ฐ ํธ์ถ๋๊ณ , ํด๋น ํจ์๋ showFullScreen ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.
showFullScreen ์ Closure ๋ก ์ค์ ํ๋๋ฐ์, ๋ณด์ฌ์ค์ผํ ์ด๋ฏธ์ง๊ฐ Cell ๋ง๋ค ๋ฌ๋ผ์ง๊ธฐ ๋๋ฌธ์ Closure ๋ก ์ค์ ํ์ต๋๋ค. ์ดํ ReviewTableViewDatasource ์์ ์ํํ ์ฝ๋๋ฅผ Closure ์ ๋๊ฒจ์ฃผ๋ ์์ผ๋ก ์์ฑํฉ๋๋ค.
class ReviewCell: UITableViewCell {
//...
typealias EmptyClosure = (() -> ())
var showFullScreen: EmptyClosure = {}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapImageSlide(_:)))
reviewImageSlide.addGestureRecognizer(tapGesture)
// ...
}
@objc func didTapImageSlide(_ sender: UITapGestureRecognizer) {
showFullScreen()
}
}
๊ทธ๋ฆฌ๊ณ ์ ์ฒดํ๋ฉด์ผ๋ก ๋ณ๊ฒฝ๋์์ ๋, ๊ธฐ์กด์ LabelPageIndicator ๋ ๋๋ฌด ์๊ธฐ๋๋ฌธ์ ํฐ ์ฌ์ด์ฆ์ Label ์ ์ ์ํด์คฌ์ต๋๋ค. ์๋ tableView ์ฝ๋์์ TopAnchor, centerXAnchor ๋ฅผ ํตํด ์๋จ ๊ฐ์ด๋ฐ์ ์์น์์ผฐ์ต๋๋ค.
class ReviewCell: UITableViewCell {
//...
let fullScreenLabelIndicator: UILabel = {
let label = UILabel()
label.textColor = .white
label.font = UIFont.systemFont(ofSize: 16)
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
}
ReviewTableViewDatasource ํ๋กํ ์ฝ ํจ์์ธ tableView(_, cellForRowAt) ํจ์์์ ์์ Closure ๋ฅผ ์ง์ ํด์ค์๋ค. ํด๋น ์ฝ๋์์๋ ํ์ฌ ํ์ด์ง์ ๋ํ Label ๋ง ์ง์ ํด์ฃผ๊ณ ์์ด์. ํ์ด์ง๊ฐ ๋ณํ ๋๋ง๋ค Label ์ ๋ณ๊ฒฝํด์ฃผ๊ธฐ ์ํด์ ImageSlideshowDelegate ํ๋กํ ์ฝ์ ์ฑํํ๊ณ ํจ์๋ฅผ ์ฌ์ ์ํฉ๋๋ค.
// MARK: TableView - Datasource
extension ReviewTableViewController: UITableViewDataSource {
// ...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// dequeueReusableCell ...
cell.showFullScreen = { [unowned self] in
let fullScreenController = cell.reviewImageSlide.presentFullScreenController(from: self, completion: nil)
fullScreenController.slideshow.pageIndicator = LabelPageIndicator()
fullScreenController.view.addSubview(fullScreenLabelIndicator)
fullScreenLabelIndicator.topAnchor.constraint(equalTo: fullScreenController.view.safeAreaLayoutGuide.topAnchor, constant: 10).isActive = true
fullScreenLabelIndicator.centerXAnchor.constraint(equalTo: fullScreenController.view.centerXAnchor).isActive = true
let currentPageString = String(cell.reviewImageSlide.currentPage + 1)
let maxPageString = String(cell.reviewImageSlide.images.count)
fullScreenLabelIndicator.text = currentPageString + "/" + maxPageString
fullScreenController.slideshow.delegate = self
}
}
}
// MARK: - ImageSlideshowDelegate
extension ReviewTableViewController: ImageSlideshowDelegate {
// ์ด๋ฏธ์ง ํ์ด์ง๊ฐ ๋ณ๊ฒฝ๋์์๋
func imageSlideshow(_ imageSlideshow: ImageSlideshow, didChangeCurrentPageTo page: Int) {
let maxPageString = String(imageSlideshow.images.count)
fullScreenLabelIndicator.text = String(page + 1) + "/" + maxPageString
}
}
์ฌ๊ธฐ๊น์ง ํ์ธํด๋ณด์๋ฉด ํฐ์น์ ์ ์ฒดํ๋ฉด์ผ๋ก ์ ํ๋๊ณ , ์๋จ์ Label Page Indicator ๊ฐ ๋ํ๋ ๊ฒ์ ํ์ธํ์ค ์ ์์ต๋๋ค! ๐คฉ ํด๋น ์ฌ์ง์ ๊ฐ๋ฐ์ค์ธ ์ดํ๊ณผ ๊ด๋ จ์ด ์์ต๋๋ค.
์ฐธ๊ณ ๋งํฌ