I have a messenger, so I want to show UIMenuController on cell long tap.
I need image view to catch long press, because I have text and media messages. But I get a crash
becomeFirstResponder
call after I received long press gesture on iOS 8(iOS 7 works well):
*** Terminating app due to uncaught exception 'UIViewControllerHierarchyInconsistency', reason: 'child view controller:<UICompatibilityInputViewController: 0x13fd75b90> should have parent view controller:<FriendPlay.WLDialogViewController: 0x13fd54d10> but requested parent is:<UIInputWindowController: 0x140815000>'
This is the part of code:
override func handleLongPress(longPress: UILongPressGestureRecognizer!) {
let alpha: CGFloat = 0.6
let point = longPress.locationInView(tableView)
let indexPath = tableView.indexPathForRowAtPoint(point)
if indexPath != nil {
let cell = tableView.cellForRowAtIndexPath(indexPath!) as MessageCell
let convertedPoint = longPress.locationInView(cell.balloonImageView)
if CGRectContainsPoint(cell.balloonImageView.frame, convertedPoint) {
var myView = cell.balloonImageView
if cell.message.type == MessageType.Text {
cell.balloonImageView.alpha = alpha
}
else {
myView = cell.mediaImageView
cell.mediaImageView.alpha = alpha
}
if longPress.state == UIGestureRecognizerState.Began {
showMenuAtPoint(convertedPoint, myView: myView)
}
}
}
}
private func showMenuAtPoint(point: CGPoint, myView: MessageImageView) {
myView.becomeFirstResponder()// <--- that crashes
let rect = CGRectMake(point.x, point.y, 0, 0)
let mc = UIMenuController.sharedMenuController()
mc.setTargetRect(rect, inView: myView)
let sendItem = UIMenuItem(title: "Send", action: "sendAgain:")
mc.menuItems = [sendItem]
mc.setMenuVisible(true, animated: true)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "menuDidHide:", name: UIMenuControllerDidHideMenuNotification, object: nil)
}
func sendAgain(sender: AnyObject) {
println("Send!")
}
For class MessageImageView
(inherited from UIImageView) I redefine becomeFirstResponder
to return always true
.
I initialize my cell in - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier messageMaxWidth:(CGFloat)messageMaxWidth
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier messageMaxWidth:(CGFloat)messageMaxWidth
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.messageMaxWidth = messageMaxWidth;
self.backgroundColor = [UIColor clearColor];
self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
self.panGesture.delegate = self;
[self addGestureRecognizer:self.panGesture];
[self setInitialSizes];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleOrientationWillChandeNote:) name:UIApplicationWillChangeStatusBarFrameNotification object:nil];
}
return self;
}
- (void)setInitialSizes
{
if (self.containerView) {
[self.containerView removeFromSuperview];
}
if (self.timeLabel) {
[self.timeLabel removeFromSuperview];
}
self.userImageView = [[UIImageView alloc] init];
self.userImageView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
self.textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, self.messageMaxWidth, 0)];
self.timeLabel = [[UILabel alloc] init];
self.mediaImageView = [[SOmessageImageView alloc] init];
self.mediaOverlayView = [[UIView alloc] init];
self.balloonImageView = [[SOmessageImageView alloc] init];
self.balloonImageView.userInteractionEnabled = YES;
if (!CGSizeEqualToSize(self.userImageViewSize, CGSizeZero)) {
CGRect frame = self.userImageView.frame;
frame.size = self.userImageViewSize;
self.userImageView.frame = frame;
}
self.userImageView.contentMode = UIViewContentModeScaleAspectFill;
self.userImageView.clipsToBounds = YES;
self.userImageView.backgroundColor = [UIColor clearColor];
self.userImageView.layer.cornerRadius = 5;
if (!CGSizeEqualToSize(self.mediaImageViewSize, CGSizeZero)) {
CGRect frame = self.mediaImageView.frame;
frame.size = self.mediaImageViewSize;
self.mediaImageView.frame = frame;
}
self.mediaImageView.contentMode = UIViewContentModeScaleAspectFill;
self.mediaImageView.clipsToBounds = YES;
self.mediaImageView.backgroundColor = [UIColor clearColor];
self.mediaImageView.userInteractionEnabled = YES;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleMediaTapped:)];
[self.mediaImageView addGestureRecognizer:tap];
self.mediaOverlayView.backgroundColor = [UIColor clearColor];
[self.mediaImageView addSubview:self.mediaOverlayView];
self.textView.textColor = [UIColor whiteColor];
self.textView.backgroundColor = [UIColor clearColor];
[self.textView setTextContainerInset:UIEdgeInsetsZero];
self.textView.textContainer.lineFragmentPadding = 0;
[self hideSubViews];
self.containerView = [[UIView alloc] initWithFrame:self.contentView.bounds];
self.containerView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
[self.contentView addSubview:self.containerView];
[self.containerView addSubview:self.balloonImageView];
[self.containerView addSubview:self.textView];
[self.containerView addSubview:self.mediaImageView];
[self.containerView addSubview:self.userImageView];
self.contentView.clipsToBounds = NO;
self.clipsToBounds = NO;
self.timeLabel.font = [UIFont fontWithName:@"AvenirNextCyr-Light" size:11];
self.timeLabel.textColor = [UIColor grayColor];
self.timeLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
UIImage *backgroundImage = [UIImage imageNamed:@"messagesDateBackground"];
if (backgroundImage) {
self.timeLabel.textColor = [UIColor whiteColor];
if (self.backgroundImageView) {
[self.backgroundImageView removeFromSuperview];
}
self.backgroundImageView = [[UIImageView alloc] initWithImage:[backgroundImage resizableImageWithCapInsets:UIEdgeInsetsMake(20, 20, 20, 20)]];
self.backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[self.contentView addSubview:self.backgroundImageView];
}
[self.contentView addSubview:self.timeLabel];
}
Please give me some suggestions, how to fix this strange bug.
Your view controller probably has a property named
inputView
that is merely a subview, not aninputView
asUIResponder
interface expects it to be.Starting with iOS 8 they check that
UIResponder
'sinputView
has no parent.