Last active
March 6, 2019 05:34
-
-
Save mntone/49b83fb59dfe5283a8335ab4ff5f4e84 to your computer and use it in GitHub Desktop.
細かい部分の調整
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
public final class ThemeSegmentedControl: UISegmentedControl { | |
private var observer: NSObjectProtocol? | |
private weak var selectedLayer: CALayer! | |
public override var frame: CGRect { | |
didSet { | |
guard let selectedLayer = selectedLayer else { return } | |
selectedLayer.frame.size.height = frame.size.height | |
selectedLayer.cornerRadius = 0.5 * frame.size.height | |
} | |
} | |
public override var selectedSegmentIndex: Int { | |
didSet { update(at: selectedSegmentIndex) } | |
} | |
public override var tintColor: UIColor! { | |
get { return themeTintColor } | |
set { | |
guard themeTintColor != newValue else { return } | |
themeTintColor = newValue | |
setupDesign() | |
} | |
} | |
private var themeTintColor: UIColor? | |
public override init(frame: CGRect) { | |
super.init(frame: frame) | |
setup() | |
} | |
public override init(items: [Any]?) { | |
super.init(items: items) | |
} | |
required init?(coder aDecoder: NSCoder) { | |
super.init(coder: aDecoder) | |
setup() | |
} | |
deinit { | |
if let observer = observer { | |
self.observer = nil | |
NotificationCenter.default.removeObserver(observer) | |
} | |
} | |
private func setup() { | |
backgroundColor = .clear | |
super.tintColor = .clear | |
addTarget(self, action: #selector(update(sender:)), for: .valueChanged) | |
observer = NotificationCenter.default | |
.addObserver(forName: UIAccessibility.darkerSystemColorsStatusDidChangeNotification, | |
object: nil, | |
queue: OperationQueue.main, | |
using: darkerSystemColorsStatusDidChange) | |
setupDesign() | |
} | |
private func darkerSystemColorsStatusDidChange(notification: Notification) { | |
if tintColor == nil { | |
setupDesign() | |
} | |
} | |
private func setupDesign() { | |
var selectedColor: UIColor | |
if let tintColor = tintColor { | |
selectedColor = tintColor | |
} else if UIAccessibility.isDarkerSystemColorsEnabled { | |
selectedColor = UIColor(red: 0.0, green: 0.25, blue: 0.87, alpha: 1.0) | |
} else { | |
selectedColor = UIColor(red: 0.0, green: 122.0 / 255.0, blue: 1.0, alpha: 1.0) | |
} | |
// Normal | |
let normalAttrs: [NSAttributedString.Key: Any] = [.foregroundColor: selectedColor] | |
setTitleTextAttributes(normalAttrs, for: .normal) | |
setTitleTextAttributes(normalAttrs, for: .highlighted) | |
// Selected | |
let selectedState: [UIControl.State] = [ | |
.selected, | |
[.selected, .highlighted], | |
] | |
let selectedAttrs: [NSAttributedString.Key: Any] = [.foregroundColor: UIColor.white] | |
selectedState.forEach { setTitleTextAttributes(selectedAttrs, for: $0) } | |
// Disable | |
let disabledAttrs: [NSAttributedString.Key: Any] = [.foregroundColor: UIColor(white: 0.48, alpha: 0.35)] | |
setTitleTextAttributes(disabledAttrs, for: .disabled) | |
let selectedLayer = self.selectedLayer ?? createSelectedLayer() | |
selectedLayer.backgroundColor = selectedColor.cgColor | |
selectedLayer.shadowColor = selectedColor.cgColor | |
if selectedSegmentIndex != -1 { | |
update(at: selectedSegmentIndex) | |
} | |
} | |
private func createSelectedLayer() -> CALayer { | |
let selectedLayer = CALayer() | |
selectedLayer.cornerRadius = 0.5 * frame.size.height | |
selectedLayer.frame.size.height = frame.size.height | |
selectedLayer.rasterizationScale = UIScreen.main.scale | |
selectedLayer.shadowOffset = CGSize(width: 0.0, height: 2.0) | |
selectedLayer.shadowOpacity = 0.4 | |
selectedLayer.shadowRadius = 2.0 | |
selectedLayer.shouldRasterize = true | |
self.selectedLayer = selectedLayer | |
layer.addSublayer(selectedLayer) | |
return selectedLayer | |
} | |
public override func layoutSubviews() { | |
super.layoutSubviews() | |
if selectedSegmentIndex != -1 { | |
update(at: selectedSegmentIndex) | |
} | |
} | |
@objc private func update(sender: ThemeSegmentedControl!) { | |
update(at: selectedSegmentIndex) | |
} | |
private func update(at index: Int) { | |
let sortedSubviews = subviews.sorted { $0.frame.origin.x < $1.frame.origin.x } | |
let selectedFrame = sortedSubviews[index].frame | |
UIView.animate(withDuration: 0.3) { | |
self.selectedLayer.frame = selectedFrame | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment