UIButton не показывает подсветку при нажатии на iOS7
Я просмотрел массу сообщений по подобным вещам, но ни один из них не соответствует или не устраняет эту проблему. Начиная с iOS 7, всякий раз, когда я добавляю UIButton
в UITableViewCell
или даже в footerview, он работает "отлично", что означает, что он получает целевое действие, но он не показывает малое выделение, которое обычно происходит, когда вы нажимаете UIButton
. Это заставляет пользовательский интерфейс выглядеть фанки, не показывая, как кнопка реагирует на касание.
Я уверен, что это считается ошибкой в iOS7, но кто-нибудь нашел решение или мог бы помочь мне найти его:)
Изменить:
Я забыл упомянуть, что он будет выделять, если я долго держу кнопку, но не быстро, как это делает, если просто добавить к стандартным представлениям.
Код:
Создание кнопки:
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.titleLabel.font = [UIFont systemFontOfSize:14];
button.titleLabel.textColor = [UIColor blueColor];
[button setTitle:@"Testing" forState:UIControlStateNormal];
[button addTarget:self action:@selector(buttonPressed:) forControlEvents: UIControlEventTouchDown];
button.frame = CGRectMake(0, 0, self.view.frame.size.width/2, 40);
Вещи, которые я тестировал:
//Удаление распознавателей жестов на UITableView
в случае, если они мешают.
for (UIGestureRecognizer *recognizer in self.tableView.gestureRecognizers) {
recognizer.enabled = NO;
}
//Удаление жестов из ячейки
for (UIGestureRecognizer *recognizer in self.contentView.gestureRecognizers) {
recognizer.enabled = NO;
}
//Это показывает малое касание, но это не желаемый внешний вид.
button.showsTouchWhenHighlighted = YES;
Ответы
Ответ 1
В этом представлении таблицы вы просто добавляете это свойство.
tableview.delaysContentTouches = NO;
И добавьте в cellForRowAtIndexPath после того, как вы инициируете ячейку, которую вы просто добавляете под кодом. Структура ячейки, по-видимому, отличается в iOS 6 и iOS 7.
iOS 7 у нас есть один элемент управления UITableViewCellScrollView Между UITableViewCell и представлением содержимого.
for (id obj in cell.subviews)
{
if ([NSStringFromClass([obj class]) isEqualToString:@"UITableViewCellScrollView"])
{
UIScrollView *scroll = (UIScrollView *) obj;
scroll.delaysContentTouches = NO;
break;
}
}
Ответ 2
Так как iOS 8 нам нужно применить ту же технику к subviews UITableView (таблица содержит скрытый вид прокрутки UITableViewWrapperView). Нет необходимости перебирать подпрограммы UITableViewCell.
for (UIView *currentView in tableView.subviews) {
if ([currentView isKindOfClass:[UIScrollView class]]) {
((UIScrollView *)currentView).delaysContentTouches = NO;
break;
}
}
Этот ответ должен быть связан с этим вопросом.
Ответ 3
Я попытался добавить это к принятому ответу, но он так и не прошел. Это гораздо более безопасный способ отключить свойство delaymentsContentTouches ячейки, поскольку он не ищет определенный класс, а скорее все, что реагирует на селектор.
В ячейке:
for (id obj in self.subviews) {
if ([obj respondsToSelector:@selector(setDelaysContentTouches:)]) {
[obj setDelaysContentTouches:NO];
}
}
В TableView:
self.tableView.delaysContentTouches = NO;
Ответ 4
Для решения, которое работает как в iOS7, так и в iOS8, создайте собственный подкласс UITableView
и пользовательский подкласс UITableViewCell
.
Используйте этот образец UITableView
initWithFrame:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// iterate over all the UITableView subviews
for (id view in self.subviews)
{
// looking for a UITableViewWrapperView
if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewWrapperView"])
{
// this test is necessary for safety and because a "UITableViewWrapperView" is NOT a UIScrollView in iOS7
if([view isKindOfClass:[UIScrollView class]])
{
// turn OFF delaysContentTouches in the hidden subview
UIScrollView *scroll = (UIScrollView *) view;
scroll.delaysContentTouches = NO;
}
break;
}
}
}
return self;
}
Используйте этот образец UITableViewCell
initWithStyle:reuseIdentifier:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self)
{
// iterate over all the UITableViewCell subviews
for (id view in self.subviews)
{
// looking for a UITableViewCellScrollView
if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewCellScrollView"])
{
// this test is here for safety only, also there is no UITableViewCellScrollView in iOS8
if([view isKindOfClass:[UIScrollView class]])
{
// turn OFF delaysContentTouches in the hidden subview
UIScrollView *scroll = (UIScrollView *) view;
scroll.delaysContentTouches = NO;
}
break;
}
}
}
return self;
}
Ответ 5
Что я сделал для решения проблемы, была категория UIButton с использованием следующего кода:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
[NSOperationQueue.mainQueue addOperationWithBlock:^{ self.highlighted = YES; }];
}
- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
[self performSelector:@selector(setDefault) withObject:nil afterDelay:0.1];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
[self performSelector:@selector(setDefault) withObject:nil afterDelay:0.1];
}
- (void)setDefault
{
[NSOperationQueue.mainQueue addOperationWithBlock:^{ self.highlighted = NO; }];
}
кнопка реагирует правильно, когда я нажимаю на нее в UITableViewCell, и мой UITableView ведет себя нормально, поскольку delaysContentTouches
не принудительно.
Ответ 6
Здесь Roman B ответит в Swift 2:
for view in tableView.subviews {
if view is UIScrollView {
(view as? UIScrollView)!.delaysContentTouches = false
break
}
}
Ответ 7
- (void)viewDidLoad
{
[super viewDidLoad];
for (id view in self.tableView.subviews)
{
// looking for a UITableViewWrapperView
if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewWrapperView"])
{
// this test is necessary for safety and because a "UITableViewWrapperView" is NOT a UIScrollView in iOS7
if([view isKindOfClass:[UIScrollView class]])
{
// turn OFF delaysContentTouches in the hidden subview
UIScrollView *scroll = (UIScrollView *) view;
scroll.delaysContentTouches = NO;
}
break;
}
}
}
![enter image description here]()
Ответ 8
Это версия Swift ответа Рафаэля Пинто выше. Не забудьте также его выставить:)
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
super.touchesBegan(touches, withEvent: event)
NSOperationQueue.mainQueue().addOperationWithBlock { () -> Void in self.highlighted = true }
}
override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) {
super.touchesCancelled(touches, withEvent: event)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_main_queue()) {
self.setDefault()
}
}
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
super.touchesEnded(touches, withEvent: event)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_main_queue()) {
self.setDefault()
}
}
func setDefault() {
NSOperationQueue.mainQueue().addOperationWithBlock { () -> Void in self.highlighted = false }
}
Ответ 9
Решение в Swift, только iOS8 (требуется дополнительная работа над каждой ячейкой для iOS7):
//
// NoDelayTableView.swift
// DivineBiblePhone
//
// Created by Chris Hulbert on 30/03/2015.
// Copyright (c) 2015 Chris Hulbert. All rights reserved.
//
// This solves the delayed-tap issue on buttons on cells.
import UIKit
class NoDelayTableView: UITableView {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
delaysContentTouches = false
// This solves the iOS8 delayed-tap issue.
// http://stackoverflow.com/questions/19256996/uibutton-not-showing-highlight-on-tap-in-ios7
for view in subviews {
if let scroll = view as? UIScrollView {
scroll.delaysContentTouches = false
}
}
}
override func touchesShouldCancelInContentView(view: UIView!) -> Bool {
// So that if you tap and drag, it cancels the tap.
return true
}
}
Чтобы использовать, все, что вам нужно сделать, это изменить класс на NoDelayTableView
в раскадровке.
Я могу подтвердить, что в iOS8 кнопки, размещенные внутри contentView в ячейке, теперь выделяются мгновенно.
Ответ 10
У меня были подобные проблемы с текстовым UIButton в UITableViewCell, не выделяющимся при прикосновении. Для меня это изменилось с помощью кнопки buttonType от Custom до System.
Установка задержекContentTouches to NO сделала трюк для UIButton только для изображения в том же UITableViewCell.
self.tableView.delaysContentTouches = NO;
![введите описание изображения здесь]()
Ответ 11
Немного измененная версия Крис Харрисон ответ. Swift 2.3:
class HighlightButton: UIButton {
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesBegan(touches, withEvent: event)
NSOperationQueue.mainQueue().addOperationWithBlock { _ in self.highlighted = true }
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
super.touchesCancelled(touches, withEvent: event)
setDefault()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesEnded(touches, withEvent: event)
setDefault()
}
private func setDefault() {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
NSOperationQueue.mainQueue().addOperationWithBlock { _ in self.highlighted = false }
}
}
}
Ответ 12
Я написал расширение категории на UITableViewCell
, чтобы упростить эту проблему. Это в основном то же самое, что и принятый ответ, за исключением того, что я поднимаю иерархию представления (в отличие от вниз) от UITableViewCell contentView
.
Я рассмотрел полностью "автоматическое" решение, которое сделало бы все ячейки, добавленные в UITableView
, установить их состояние delaysContentTouches
в соответствии с состоянием UITableView
delaysContentTouches
. Для выполнения этой работы мне придется либо swizzle UITableView
, либо потребовать от разработчика использовать подкласс UITableView
. Не желая требовать, чтобы я решился на это решение, которое, по моему мнению, проще и гибче.
Расширение категории и выборка проводов здесь:
https://github.com/TomSwift/UITableViewCell-TS_delaysContentTouches
Он мертв-прост в использовании:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// using static cells from storyboard...
UITableViewCell* cell = [super tableView: tableView cellForRowAtIndexPath: indexPath];
cell.ts_delaysContentTouches = NO;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
Здесь код для категории:
@interface UITableViewCell (TS_delaysContentTouches)
@property (nonatomic, assign) BOOL ts_delaysContentTouches;
@end
@implementation UITableViewCell (TS_delaysContentTouches)
- (UIScrollView*) ts_scrollView
{
id sv = self.contentView.superview;
while ( ![sv isKindOfClass: [UIScrollView class]] && sv != self )
{
sv = [sv superview];
}
return sv == self ? nil : sv;
}
- (void) setTs_delaysContentTouches:(BOOL)delaysContentTouches
{
[self willChangeValueForKey: @"ts_delaysContentTouches"];
[[self ts_scrollView] setDelaysContentTouches: delaysContentTouches];
[self didChangeValueForKey: @"ts_delaysContentTouches"];
}
- (BOOL) ts_delaysContentTouches
{
return [[self ts_scrollView] delaysContentTouches];
}
@end
Ответ 13
Принятый ответ не работал на некоторых "кранах" для меня.
Наконец, я добавляю следующий код в категорию uibutton (/subclass), и он работает на сто процентов.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.backgroundColor = [UIColor greenColor];
[UIView animateWithDuration:0.05 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
self.backgroundColor = [UIColor clearColor];
} completion:^(BOOL finished)
{
}];
[super touchesBegan:touches withEvent:event];
}
Ответ 14
Поскольку objc является динамическим, и scrollView является единственным классом, который реагирует на задержки .ContentTouches, это должно работать как для ios 7, так и для 8 (поместите его где-нибудь в начале вашего TableViewController, например awakeFromNib):
for (id view in self.tableView.subviews)
{
if ([view respondsToSelector:@selector(delaysContentTouches)]) {
UIScrollView *scrollView = (UIScrollView *)view;
scrollView.delaysContentTouches = NO;
break;
}
}
Вам также может потребоваться отключить "delayaysContentTouches" в вашем раскадровке или кегли, выбрав таблицу внутри вашего viewController. Кстати, это может не работать на ios 7, если вы используете tableView внутри viewController, по крайней мере, я не мог заставить его работать.
Ответ 15
Это решение для меня не работает, я исправлено подклассов TableView и реализации этих двух методов
- (instancetype)initWithCoder:(NSCoder *)coder{
self = [super initWithCoder:coder];
if (self) {
for (id obj in self.subviews) {
if ([obj respondsToSelector:@selector(setDelaysContentTouches:)]){
[obj performSelector:@selector(setDelaysContentTouches:) withObject:NO];
}
}
}
return self;
}
- (BOOL)delaysContentTouches{
return NO;
}
Ответ 16
Решение в Swift для iOS 7 и 8:
Сначала я написал служебную функцию:
class func classNameAsString(obj: AnyObject) -> String {
return _stdlib_getDemangledTypeName(obj).componentsSeparatedByString(".").last!
}
тогда я подклассифицирую UITableView и реализую это:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
for view in self.subviews {
if (Utility.classNameAsString(view) == "UITableViewWrapperView") {
if view.isKindOfClass(UIScrollView) {
var scroll = (view as UIScrollView)
scroll.delaysContentTouches = false
}
break
}
}
}
Я также подклассифицирую UITableViewCell и реализую это:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
for view in self.subviews {
if (Utility.classNameAsString(view) == "UITableViewCellScrollView") {
if view.isKindOfClass(UIScrollView) {
var scroll = (view as UIScrollView)
scroll.delaysContentTouches = false
}
}
}
}
В моем случае запускается init (coder:). Поместите точку отладки в свои функции init, чтобы узнать, какая функция init будет запущена, а затем с помощью приведенного выше кода, чтобы она работала.
Надеюсь помочь кому-то.
Ответ 17
В Swift 3 это расширение UIView можно использовать в UITableViewCell. Предпочтительно в методе cellForRowAt
.
func removeTouchDelayForSubviews() {
for subview in subviews {
if let scrollView = subview as? UIScrollView {
scrollView.delaysContentTouches = false
} else {
subview.removeTouchDelayForSubviews()
}
}
}