Last active
March 27, 2017 15:54
-
-
Save kazuhiro4949/6ba1e46494dbb46d79f0e1f2a381f692 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
class TextView: UITextView { | |
lazy var moreLabel: UILabel = { | |
let label = UILabel() | |
label.text = "さらに表示" | |
label.textColor = .gray | |
label.font = self.font | |
label.textAlignment = .center | |
return label | |
}() | |
override func awakeFromNib() { | |
super.awakeFromNib() | |
textContainer.lineBreakMode = .byTruncatingTail | |
isScrollEnabled = false | |
isUserInteractionEnabled = true | |
isSelectable = true | |
textContainer.maximumNumberOfLines = 5 | |
textContainerInset = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) | |
translatesAutoresizingMaskIntoConstraints = true | |
addSubview(moreLabel) | |
} | |
override func layoutSubviews() { | |
super.layoutSubviews() | |
sizeToFit() | |
moreLabel.sizeToFit() | |
do { | |
let x = bounds.width - moreLabel.bounds.width - textContainerInset.right | |
let y = bounds.height - moreLabel.bounds.height - textContainerInset.bottom | |
moreLabel.frame.origin = CGPoint(x: x, y: y) | |
} | |
let exclusivePath = UIBezierPath(rect: moreLabel.frame) | |
textContainer.exclusionPaths = [exclusivePath] | |
} | |
} | |
class VisualEffectView: UIVisualEffectView, FocusEffectable { | |
var focusEffect: FocusEffect = FocusEffect() | |
override func awakeFromNib() { | |
super.awakeFromNib() | |
effect = nil | |
} | |
override var canBecomeFocused: Bool { | |
return true | |
} | |
override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) { | |
super.didUpdateFocus(in: context, with: coordinator) | |
if let item = context.nextFocusedItem as? VisualEffectView, item == self { | |
coordinator.addCoordinatedAnimations({ [weak self] in | |
self?.activateEffect(isActivated: true) | |
self?.effect = UIBlurEffect(style: .light) | |
}, completion: {}) | |
} else if let item = context.previouslyFocusedItem as? VisualEffectView, item == self { | |
coordinator.addCoordinatedAnimations({ [weak self] in | |
self?.activateEffect(isActivated: false) | |
self?.effect = nil | |
}, completion: {}) | |
} | |
} | |
override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) { | |
UIView.animate(withDuration: 0.2, animations: { [weak self] in | |
self?.transform = .identity | |
}) { (finish) in } | |
} | |
override func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) { | |
UIView.animate(withDuration: 0.2, animations: { [weak self, activatedScale = activatedScale] in | |
self?.transform = activatedScale | |
}) { (finish) in } | |
} | |
} | |
struct FocusEffect { | |
let motionEffectGroup: UIMotionEffectGroup = { | |
let yTilt = UIInterpolatingMotionEffect(keyPath: "center.y", type: .tiltAlongVerticalAxis) | |
yTilt.maximumRelativeValue = 7 | |
yTilt.minimumRelativeValue = -7 | |
let tiltAngle = CGFloat(2 * M_PI / 180) | |
var minY = CATransform3DIdentity | |
minY.m34 = 1.0 / 500 | |
minY = CATransform3DRotate(minY, -tiltAngle, 1, 0, 0) | |
var maxY = CATransform3DIdentity | |
maxY.m34 = minY.m34 | |
maxY = CATransform3DRotate(maxY, tiltAngle, 1, 0, 0) | |
let verticalTiltEffect = UIInterpolatingMotionEffect(keyPath: "layer.transform", type: .tiltAlongVerticalAxis) | |
verticalTiltEffect.minimumRelativeValue = NSValue(caTransform3D: maxY) | |
verticalTiltEffect.maximumRelativeValue = NSValue(caTransform3D: minY) | |
let motionEffectGroup = UIMotionEffectGroup() | |
motionEffectGroup.motionEffects = [yTilt, verticalTiltEffect] | |
return motionEffectGroup | |
}() | |
} | |
protocol FocusEffectable: class { | |
var focusEffect: FocusEffect { get set } | |
var activatedScale: CGAffineTransform { get } | |
func activateShadow(isActivated: Bool) | |
func activateEffect(isActivated: Bool) | |
} | |
extension FocusEffectable where Self: UIView { | |
var activatedScale: CGAffineTransform { | |
return CGAffineTransform(scaleX: 1.05, y: 1.05) | |
} | |
func activateShadow(isActivated: Bool) { | |
if isActivated { | |
layer.masksToBounds = false | |
layer.shadowColor = UIColor.black.cgColor | |
layer.shadowRadius = 30 | |
layer.shadowOffset = CGSize(width: 0, height: 20) | |
layer.shadowOpacity = 0.3 | |
} else { | |
layer.masksToBounds = false | |
layer.shadowColor = UIColor.clear.cgColor | |
layer.shadowRadius = 0 | |
layer.shadowOffset = CGSize(width: 0, height: 0) | |
layer.shadowOpacity = 0 | |
} | |
} | |
func activateEffect(isActivated: Bool) { | |
if isActivated { | |
transform = activatedScale | |
activateShadow(isActivated: true) | |
addMotionEffect(focusEffect.motionEffectGroup) | |
} else { | |
transform = .identity | |
activateShadow(isActivated: false) | |
removeMotionEffect(focusEffect.motionEffectGroup) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment