如何像 Apple 一样突出显示 UIView
Posted
技术标签:
【中文标题】如何像 Apple 一样突出显示 UIView【英文标题】:How to highlight a UIView like Apple does 【发布时间】:2014-02-08 05:40:29 【问题描述】:当用户触摸 UIButton 时,它会变灰一点。什么苹果能达到这样的效果?当我的自定义 UIButton 突出显示时,我需要它具有相同的效果。
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
AppDelegate* appDelegate=(AppDelegate*)[UIApplication sharedApplication].delegate;
if ([keyPath isEqualToString:@"highlighted"])
UIButton *button = object;
if (button.isHighlighted)
self.backgroundColor=[UIColor colorWithRed:36.0/255.0 green:153.0/255.0 blue:116.0/255.0 alpha:1];
else
self.backgroundColor=appDelegate.currentAppColor;
我正在使用此代码,但更改背景颜色不会影响任何子视图。我也需要它们变灰。
【问题讨论】:
我也在寻找解决方案,但我相当肯定 Apple 正在做一些更复杂的事情。看起来它确定了图像的蒙版并仅使那些区域变暗。不太清楚他们是怎么做到的。 我有简单的解决方案,请参考:***.com/a/48161904/6630644 【参考方案1】:我认为对此没有简单或明确的答案。
免责声明: 此答案中的所有代码都是从我的脑海中编写的,所以请原谅错误。
我建议这样做:
建议一:降低所有视图子视图的不透明度,这不会影响颜色...
目标 C:
-(void)buttonTouched
for(UIView *subview in self.subviews)
subview.alpha = 0.5;
斯威夫特:
func buttonTouched()
for subview in subviews
subview.alpha = 0.5
建议 2(未测试):尝试通过手动操作来覆盖所有子视图(缺点:您还必须手动设置颜色,如果是这样,那将是疯狂的不是单色的):
目标 C:
-(void)buttonTouched
for(UIView *subview in self.subviews)
if([subview respondsToSelector:@selector(setBackgroundColor:)])
//for generic views - changes UILabel's backgroundColor too, though
subview.backgroundColor = [UIColor grayColor];
if([subview respondsToSelector:@selector(setTextColor:)])
//reverse effect of upper if statement(if needed)
subview.backgroundColor = [UIColor clearColor];
subview.textColor = [UIColor grayColor];
斯威夫特:
func buttonTouched()
for subview in subviews
if subview.responds(to: #selector(setter: AVMutableVideoCompositionInstruction.backgroundColor))
//for generic views - changes UILabel's backgroundColor too, though
subview.backgroundColor = UIColor.gray
if subview.responds(to: #selector(setter: UILabel.textColor))
//reverse effect of upper if statement(if needed)
subview.backgroundColor = UIColor.clear
subview.textColor = UIColor.gray
这是一个非常糟糕的设计,可能会导致很多问题,但它可能会对您有所帮助。上面的例子需要很多改进,我只是想给你一个提示。您必须恢复 touchesEnded: 方法中的颜色。也许对你有帮助……
建议 3:用透明视图(如果是矩形)覆盖整个视图
目标 C:
-(void)buttonTouched
UIView *overlay = [[UIView alloc]initWithFrame:self.bounds];
overlay.backgroundColor = [[UIColor grayColor]colorWithAlphaComponent:0.5];
[self addSubview: overlay];
斯威夫特:
func buttonTouched()
let overlay = UIView(frame: bounds)
overlay.backgroundColor = UIColor.gray.withAlphaComponent(0.5)
addSubview(overlay)
当然,当用户松开手指时,您必须将其移除。
建议 4:另一种选择是创建当前视图的位图并根据自己的喜好修改像素,这是一项相当多的工作,因此我将在此处省略代码。
Apple 可能会混合使用后两者。当一个按钮被触摸时,它将越过像素并在每个具有 alpha 分量的像素上覆盖一个灰色像素。
我希望我能帮上忙。
【讨论】:
我想到了你的方法3,最后还是用了它。 很高兴我能帮上忙 :-)【参考方案2】:结束了这段代码
maskView=[[UIView alloc]initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
maskView.backgroundColor=[[UIColor blackColor]colorWithAlphaComponent:0.5];
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
if ([keyPath isEqualToString:@"highlighted"])
UIButton *button = object;
if (button.isHighlighted)
[self addSubview:maskView];
else
[maskView removeFromSuperview];
【讨论】:
【参考方案3】:为你的 UIView 创建一个点击手势
UITapGestureRecognizer* buttonViewTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(categoryButtonAction:)];
现在将以下定义添加到您的代码中。它会在视图中产生一些相似的效果。
-(void)touchGestureAction:(UIGestureRecognizer*)gesture
UIView * sender = gesture.view;
UIColor *color = sender.backgroundColor;
sender.backgroundColor = [UIColor whiteColor];
sender.alpha = 0.7;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC);
// This will create flash effect
dispatch_after(popTime, dispatch_get_main_queue(), ^(void)
sender.backgroundColor = color;
sender.alpha = 1.0;
);
这将创建一些与按钮触摸效果非常相似的效果。
【讨论】:
【参考方案4】:我知道这是一个老问题。但是,如果有人仍在寻找通用的触摸高亮解决方案,我创建了一个小类别来解决这个问题。
https://github.com/mta452/UIView-TouchHighlighting
用法:
只需在视图控制器中导入类别并在 viewDidLoad 中添加以下行。
buttonView.touchHighlightingStyle = MTHighlightingStyleHollowDarkOverlay;
不同的突出显示样式:
【讨论】:
您的分类看起来不错,但实际上它适用于所有 UIView。在应用程序的所有视图中都替换了有关触摸事件的方法。 是的,这是通过方法调配完成的,因此所有视图都会受到影响。但这没什么大不了的,因为这些方法仅在触摸发生时才调用,因此不会影响性能。其发展背后的基本思想是将现有观点转换为突出观点。可能有一个 UIView 的子类,但它会对现有的代码库产生很大影响。 如果我错了,请纠正我。方法 swizzling 是在 load 方法中创建的。它会从一开始就被调用(不是你说的“只有在触摸发生时才调用)。如果你将断点放在方法swizzling中,你会看到。关于子类化,你可能是对的。但是,必须实现子类化对于所有 UIControl(例如,UILabel、UIButton、UICollectionView 等) 你说得对,方法调配是在加载方法中创建的。但是这些 swizzled 方法仅在发生触摸时才被调用。处理高亮状态后,调用原始实现。它的工作方式类似于具有重写方法的子类。 这是一种向任何元素添加类似按钮的行为的快速方法,尽管为整个视图控制器执行此操作感觉很奇怪,如果我只想在类中使用它,我该怎么办继承自 UILabel?【参考方案5】:斯威夫特 3:
在您的自定义 UIView 类中覆盖 touchesBegan
和 touchesEnded
回调
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
self.layer.backgroundColor = UIColor.white.cgColor
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?)
self.layer.backgroundColor = UIColor.gray.cgColor
或者更好地使用阴影而不是改变背景
CardView 代码,除了从https://github.com/aclissold/CardView 借来的 touches 事件
@IBDesignable
class CardView: UIView
@IBInspectable var cornerRadius: CGFloat = 5
@IBInspectable var shadowOffsetWidth: Int = 0
@IBInspectable var shadowOffsetHeight: Int = 1
@IBInspectable var shadowColor: UIColor? = UIColor.black
@IBInspectable var shadowOpacity: Float = 0.23
override func layoutSubviews()
layer.cornerRadius = cornerRadius
let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius)
layer.masksToBounds = false
layer.shadowColor = shadowColor?.cgColor
layer.shadowOffset = CGSize(width: shadowOffsetWidth, height: shadowOffsetHeight);
layer.shadowOpacity = shadowOpacity
layer.shadowPath = shadowPath.cgPath
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
layer.shadowOffset = CGSize(width: shadowOffsetWidth, height: shadowOffsetHeight * 2);
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?)
layer.shadowOffset = CGSize(width: shadowOffsetWidth, height:
shadowOffsetHeight);
更新:
我还添加了touchesCancelled
回调以防止我的UIView
卡在选定状态。
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?)
layer.shadowOffset = CGSize(width: shadowOffsetWidth, height: shadowOffsetHeight);
【讨论】:
【参考方案6】:想法:
添加要触发触摸区域的按钮。
使用事件:Touch Down、Touch Up Inside 和 Touch Up Outside
在Touch Down设置Highlight状态值,其他设置Normal vale。
您可以使用情节提要 IBAction 来做,或以编程方式。
示例代码(以编程方式):
- (void)viewDidLoad
[super viewDidLoad];
firstView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)];
firstView.backgroundColor = [UIColor blueColor];
firstBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 300, 300)];
[firstBtn addTarget:self action:@selector(touchDownCollection) forControlEvents:UIControlEventTouchDown];
[firstBtn addTarget:self action:@selector(touchUpInSideCollection) forControlEvents:UIControlEventTouchUpInside];
[firstBtn addTarget:self action:@selector(touchUpOutSideCollection) forControlEvents:UIControlEventTouchUpOutside];
[self.view addSubview:firstView];
[self.view addSubview:firstBtn];
//Need add: firstView.userInteractionEnabled = NO; if
//[self.view addSubview:firstBtn];
//[self.view addSubview:firstView];
- (void)touchDownCollection
// Highlight state value: alpha, background...
firstView.alpha = 0.5;
- (void)touchUpInSideCollection
// Normal state value.
firstView.alpha = 1.0;
- (void)touchUpOutSideCollection
// Normal state value.
firstView.alpha = 1.0;
【讨论】:
【参考方案7】:您可以使用自定义视图,例如:
class HighlightView: UIView
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
DispatchQueue.main.async
self.alpha = 1.0
UIView.animate(withDuration: 0.4, delay: 0.0, options: .curveLinear, animations:
self.alpha = 0.5
, completion: nil)
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?)
DispatchQueue.main.async
self.alpha = 0.5
UIView.animate(withDuration: 0.4, delay: 0.0, options: .curveLinear, animations:
self.alpha = 1.0
, completion: nil)
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?)
DispatchQueue.main.async
self.alpha = 0.5
UIView.animate(withDuration: 0.4, delay: 0.0, options: .curveLinear, animations:
self.alpha = 1.0
, completion: nil)
然后你可以使用它来代替UIView
,当你点击它时,它会改变它的alpha
值,所以它看起来像一个亮点。
【讨论】:
记得在重写这些方法时调用超级实现,如documentation 所述。以上是关于如何像 Apple 一样突出显示 UIView的主要内容,如果未能解决你的问题,请参考以下文章
UIView 中的“BOOL 突出显示”属性而不是 UITableViewCell?
WinForms TreeView - 如何手动“突出显示”节点(就像点击它一样)
如何突出显示带有孩子的 div(带有部分不透明层?)就像雅虎邮件一样,参见图片