我要做的就是为所有状态的按钮添加背景颜色。但是我想保持在tvOS
情节提要中使用系统按钮时“免费”获得的自动焦点阴影。到目前为止,我还没有找到允许这样做的组合。
或者,我也对一种在按钮获得焦点时以编程方式添加阴影的方法感兴趣,但没有对按钮进行子类化(我还没有尝试过),我也不知道该怎么做。
您可以像这样为自定义按钮添加阴影:
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
{
context.nextFocusedView.layer.shadowOffset = CGSizeMake(0, 10);
context.nextFocusedView.layer.shadowOpacity = 0.6;
context.nextFocusedView.layer.shadowRadius = 15;
context.nextFocusedView.layer.shadowColor = [UIColor blackColor].CGColor;
context.previouslyFocusedView.layer.shadowOpacity = 0;
}
对简单的颜色更改不满意,所以我制作了一个自定义按钮子类,使其看起来更像是使用系统按钮获得的默认动画 -
class CustomButton: UIButton
{
private var initialBackgroundColour: UIColor!
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
initialBackgroundColour = backgroundColor
}
override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator)
{
coordinator.addCoordinatedAnimations(
{
if self.focused
{
self.backgroundColor = UIColor.whiteColor()
UIView.animateWithDuration(0.2, animations:
{
self.transform = CGAffineTransformMakeScale(1.1, 1.1)
},
completion:
{
finished in
UIView.animateWithDuration(0.2, animations:
{
self.transform = CGAffineTransformIdentity
},
completion: nil)
})
}
else
{
self.backgroundColor = self.initialBackgroundColour
}
},
completion: nil)
}
}
没什么太复杂的,但可以完成工作
覆盖didUpdateFocusInContext
方法并检查下一个焦点视图是否为按钮,如果是,则自定义其 UI,并将其设置回原始状态检查context.previousFocusedView
该按钮,如下所示
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
{
if (context.nextFocusedView == _button)
{
// set background color
}
else if (context.previousFocusedView == _button)
{
// set background color to background
}
}
灵感来自 SomaMan 的终极解决方案。只需对所有自定义按钮进行子类化,即可获得:
包括:点击动画和释放和拖走。
//
// CustomFocusButton.swift
//
import UIKit
class CustomFocusButton: UIButton {
let focusedScaleFactor : CGFloat = 1.2
let focusedShadowRadius : CGFloat = 10
let focusedShadowOpacity : Float = 0.25
let shadowColor = UIColor.blackColor().CGColor
let shadowOffSetFocused = CGSizeMake(0, 27)
let animationDuration = 0.2
override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator)
{
coordinator.addCoordinatedAnimations({
if self.focused{
UIView.animateWithDuration(self.animationDuration, animations:{ [weak self] () -> Void in
guard let weakSelf = self else {return}
weakSelf.transform = CGAffineTransformMakeScale(weakSelf.focusedScaleFactor, weakSelf.focusedScaleFactor)
weakSelf.clipsToBounds = false
weakSelf.layer.shadowOpacity = weakSelf.focusedShadowOpacity
weakSelf.layer.shadowRadius = weakSelf.focusedShadowRadius
weakSelf.layer.shadowColor = weakSelf.shadowColor
weakSelf.layer.shadowOffset = weakSelf.shadowOffSetFocused
},completion:{ [weak self] finished in
guard let weakSelf = self else {return}
if !finished{
weakSelf.transform = CGAffineTransformMakeScale(weakSelf.focusedScaleFactor, weakSelf.focusedScaleFactor)
weakSelf.clipsToBounds = false
weakSelf.layer.shadowOpacity = weakSelf.focusedShadowOpacity
weakSelf.layer.shadowRadius = weakSelf.focusedShadowRadius
weakSelf.layer.shadowColor = weakSelf.shadowColor
weakSelf.layer.shadowOffset = weakSelf.shadowOffSetFocused
}
})
} else {
UIView.animateWithDuration(self.animationDuration, animations:{ [weak self] () -> Void in
guard let weakSelf = self else {return}
weakSelf.clipsToBounds = true
weakSelf.transform = CGAffineTransformIdentity
}, completion: {[weak self] finished in
guard let weakSelf = self else {return}
if !finished{
weakSelf.clipsToBounds = true
weakSelf.transform = CGAffineTransformIdentity
}
})
}
}, completion: nil)
}
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
UIView.animateWithDuration(animationDuration, animations: { [weak self] () -> Void in
guard let weakSelf = self else {return}
weakSelf.transform = CGAffineTransformIdentity
weakSelf.layer.shadowOffset = CGSizeMake(0, 10);
})
}
override func pressesCancelled(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
if focused{
UIView.animateWithDuration(animationDuration, animations: { [weak self] () -> Void in
guard let weakSelf = self else {return}
weakSelf.transform = CGAffineTransformMakeScale(weakSelf.focusedScaleFactor, weakSelf.focusedScaleFactor)
weakSelf.layer.shadowOffset = weakSelf.shadowOffSetFocused
})
}
}
override func pressesEnded(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
if focused{
UIView.animateWithDuration(animationDuration, animations: {[weak self] () -> Void in
guard let weakSelf = self else {return}
weakSelf.transform = CGAffineTransformMakeScale(weakSelf.focusedScaleFactor, weakSelf.focusedScaleFactor)
weakSelf.layer.shadowOffset = weakSelf.shadowOffSetFocused
})
}
}
}
我发现了更好的东西:
-(void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator {
[coordinator addCoordinatedAnimations:^{
if (self.focused) {
self.backgroundColor = [UIColor whiteColor];
}
else {
self.backgroundColor = [UIColor clearColor];
}
} completion:nil];
}
Swift 4 /tvOS11 及更好:
将 Interface Builder 按钮属性中的 ButtonType 设置为“Plain”。
将此私有扩展添加到您的课程中:
private extension UIImage {
static func imageWithColor(color: UIColor, size: CGSize) -> UIImage? {
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.setFill()
UIRectFill(rect)
let image: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
然后在您连接的 IBOutlet 中为按钮的焦点状态设置背景图像:
@IBOutlet weak var myButton: UIButton! {
didSet {
let backgroundImageSelected = UIImage.imageWithColor(color: .red, size: myButton.bounds.size)
myButton.setBackgroundImage(backgroundImageSelected, for: .focused)
}
}
您可以将情节提要中的背景图像设置为包含您想要的颜色的图像
您可以使用该UIButton
方法setBackgroundImage(image: UIImage?, forState state: UIControlState)
并传递一个平面颜色和状态的图像.Normal
。
此图像可以很容易地以编程方式从 aUIColor
和 1x1 的大小创建:
func getImageWithColor(color: UIColor, size: CGSize) -> UIImage {
let rect = CGRectMake(0, 0, size.width, size.height)
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.setFill()
UIRectFill(rect)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}