From 7f387b49d195417083528c087904d9564077bc76 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 12:53:18 +0800 Subject: [PATCH 01/16] add BubbleMenuView --- Yep.xcodeproj/project.pbxproj | 12 ++ Yep/Base.lproj/Main.storyboard | 2 +- .../ConversationViewController.swift | 27 +++- Yep/Views/BubbleMenu/BubbleMenuView.swift | 136 ++++++++++++++++++ 4 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 Yep/Views/BubbleMenu/BubbleMenuView.swift diff --git a/Yep.xcodeproj/project.pbxproj b/Yep.xcodeproj/project.pbxproj index 21ff1372..ac671dc0 100644 --- a/Yep.xcodeproj/project.pbxproj +++ b/Yep.xcodeproj/project.pbxproj @@ -97,6 +97,7 @@ 5039594F1B05E6E000797A3E /* ProfileSocialAccountGithubCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5039594D1B05E6E000797A3E /* ProfileSocialAccountGithubCell.xib */; }; 503A54ED1B328ADB002077BD /* NSLocale+Yep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503A54EC1B328ADB002077BD /* NSLocale+Yep.swift */; }; 503CAB431AC00CB100DFE830 /* ConversationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 503CAB421AC00CB100DFE830 /* ConversationViewController.swift */; }; + 5044BF061B5FA74800930ADC /* BubbleMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5044BF051B5FA74800930ADC /* BubbleMenuView.swift */; }; 504BDC151B4528A500DBD35D /* Badges.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 504BDC141B4528A500DBD35D /* Badges.xcassets */; }; 504CBA3D1B3D04B800663A90 /* ChatTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504CBA3C1B3D04B800663A90 /* ChatTextView.swift */; }; 504F41251ACE2D1D00FBB19A /* SampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504F41241ACE2D1D00FBB19A /* SampleView.swift */; }; @@ -321,6 +322,7 @@ 5039594D1B05E6E000797A3E /* ProfileSocialAccountGithubCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ProfileSocialAccountGithubCell.xib; path = Views/Cells/ProfileSocialAccount/ProfileSocialAccountGithubCell.xib; sourceTree = ""; }; 503A54EC1B328ADB002077BD /* NSLocale+Yep.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSLocale+Yep.swift"; path = "Extensions/NSLocale+Yep.swift"; sourceTree = ""; }; 503CAB421AC00CB100DFE830 /* ConversationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConversationViewController.swift; path = ViewControllers/Conversation/ConversationViewController.swift; sourceTree = ""; }; + 5044BF051B5FA74800930ADC /* BubbleMenuView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BubbleMenuView.swift; path = Views/BubbleMenu/BubbleMenuView.swift; sourceTree = ""; }; 504BDC141B4528A500DBD35D /* Badges.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Badges.xcassets; sourceTree = ""; }; 504CBA3C1B3D04B800663A90 /* ChatTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChatTextView.swift; path = Views/TextViews/ChatTextView.swift; sourceTree = ""; }; 504F41241ACE2D1D00FBB19A /* SampleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SampleView.swift; path = Views/AudioWaves/SampleView.swift; sourceTree = ""; }; @@ -782,6 +784,7 @@ 5019F62F1B39BFCB0000D993 /* ConversationMore */, 500A0B201B451A7400D49358 /* Badge */, 504F85AD1B4D21E400F909BE /* DiscoverFilter */, + 5044BF071B5FA75000930ADC /* BubbleMenu */, ); name = Views; sourceTree = ""; @@ -1030,6 +1033,14 @@ name = Conversation; sourceTree = ""; }; + 5044BF071B5FA75000930ADC /* BubbleMenu */ = { + isa = PBXGroup; + children = ( + 5044BF051B5FA74800930ADC /* BubbleMenuView.swift */, + ); + name = BubbleMenu; + sourceTree = ""; + }; 504CBA3B1B3D048900663A90 /* TextViews */ = { isa = PBXGroup; children = ( @@ -1802,6 +1813,7 @@ 5023DE2A1AB685BA00B3EE96 /* ContactsViewController.swift in Sources */, 50CDBE491ACBAD3200459CE0 /* ChatLeftImageCell.swift in Sources */, 5033159C1AC101C80008A209 /* ChatRightTextCell.swift in Sources */, + 5044BF061B5FA74800930ADC /* BubbleMenuView.swift in Sources */, 5023DE561AB6CA1000B3EE96 /* AvatarCache.swift in Sources */, 5023DE371AB6979600B3EE96 /* ConversationCell.swift in Sources */, 502AE5351AB8649F005BD199 /* LoginByMobileViewController.swift in Sources */, diff --git a/Yep/Base.lproj/Main.storyboard b/Yep/Base.lproj/Main.storyboard index d9095c0b..24bc0f63 100644 --- a/Yep/Base.lproj/Main.storyboard +++ b/Yep/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - + diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index f601d591..418879b2 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -634,8 +634,6 @@ class ConversationViewController: BaseViewController { override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) - - conversationCollectionViewHasBeenMovedToBottomOnce = true FayeService.sharedManager.delegate = self @@ -668,6 +666,31 @@ class ConversationViewController: BaseViewController { self.navigationController?.setNavigationBarHidden(false, animated: true) self.setNeedsStatusBarAppearanceUpdate() + + + // test menu + + if true { + let menu = BubbleMenuView(titles: ["Copy", "Delete"]) + menu.setTranslatesAutoresizingMaskIntoConstraints(false) + view.addSubview(menu) + + let menuCenterY = NSLayoutConstraint(item: menu, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: 0) + let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: 0) + + NSLayoutConstraint.activateConstraints([menuCenterY, menuCenterX]) + } + + if true { + let menu = BubbleMenuView(titles: ["Copy"]) + menu.setTranslatesAutoresizingMaskIntoConstraints(false) + view.addSubview(menu) + + let menuCenterY = NSLayoutConstraint(item: menu, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: -100) + let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: 0) + + NSLayoutConstraint.activateConstraints([menuCenterY, menuCenterX]) + } } private func markMessageAsReaded(message: Message) { diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift new file mode 100644 index 00000000..a9bb30ed --- /dev/null +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -0,0 +1,136 @@ +// +// BubbleMenuView.swift +// Yep +// +// Created by NIX on 15/7/22. +// Copyright (c) 2015年 Catch Inc. All rights reserved. +// + +import UIKit + +class BubbleMenuView: UIView { + + var titles: [String] + + var buttons = [UIButton]() + + init(titles: [String]) { + self.titles = titles + super.init(frame: CGRectZero) + + makeUI() + } + + required init(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + let arrowHeight: CGFloat = 8 + let buttonGap: CGFloat = 12 + + func makeUI() { + + //backgroundColor = UIColor.redColor() + backgroundColor = UIColor.clearColor() + + var format = "H:|" + + for (index, title) in enumerate(titles) { + + let button = UIButton() + //button.backgroundColor = UIColor.blueColor().colorWithAlphaComponent(0.5) + + button.setTitle(title, forState: .Normal) + button.setTranslatesAutoresizingMaskIntoConstraints(false) + + addSubview(button) + + buttons.append(button) + + if index == 0 { + format += "-[button\(index)]" + } else { + format += "-(\(buttonGap))-[button\(index)(==button0)]" + } + } + + format += "-|" + + //let format = "H:|[label0][label1][label2]|" + + var views = [NSObject: AnyObject]() + + for (index, button) in enumerate(buttons) { + let key = "button\(index)" + views[key] = button + } + + let hConstraints = NSLayoutConstraint.constraintsWithVisualFormat(format, options: .AlignAllCenterY, metrics: nil, views: views) + + NSLayoutConstraint.activateConstraints(hConstraints) + + if let firstButton = buttons.first { + + let firstButtonTop = NSLayoutConstraint(item: firstButton, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0) + let firstButtonBottom = NSLayoutConstraint(item: firstButton, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1, constant: -arrowHeight) + + NSLayoutConstraint.activateConstraints([firstButtonTop, firstButtonBottom]) + } + } + +// override func intrinsicContentSize() -> CGSize { +// return CGSize(width: 80 * titles.count, height: 80) +// } + + + override func drawRect(rect: CGRect) { + + UIColor.blackColor().colorWithAlphaComponent(0.7).setFill() + + // bubble + + var roundedRect = rect + roundedRect.size.height -= arrowHeight + let bubblePath = UIBezierPath(roundedRect: roundedRect, cornerRadius: 5) + bubblePath.fill() + + + // arrow + + let buttomX = CGRectGetMidX(rect) + let buttomY = CGRectGetMaxY(rect) + + let arrowPath = UIBezierPath() + arrowPath.moveToPoint(CGPointMake(buttomX, buttomY)) + arrowPath.addLineToPoint(CGPointMake(buttomX - (arrowHeight - 1), buttomY - arrowHeight)) + arrowPath.addLineToPoint(CGPointMake(buttomX + (arrowHeight - 1), buttomY - arrowHeight)) + arrowPath.closePath() + arrowPath.fill() + + + // lines + + UIColor.whiteColor().colorWithAlphaComponent(0.3).setStroke() + + for (index, button) in enumerate(buttons) { + if index > 0 { + let line = UIBezierPath() + + let x = CGRectGetMinX(button.frame) - buttonGap * 0.5 + let y = CGRectGetMaxY(rect) + + line.moveToPoint(CGPoint(x: x , y: 0)) + line.addLineToPoint(CGPoint(x: x, y: y)) + + line.lineWidth = 1 + + line.stroke() + } + } + } + +} + + + + From 6bfab45aabd726f225bd49b1f9c7a5c67214d401 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 13:08:55 +0800 Subject: [PATCH 02/16] set BubbleMenuView Item action --- .../ConversationViewController.swift | 20 ++++++++- Yep/Views/BubbleMenu/BubbleMenuView.swift | 42 ++++++++++++------- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 418879b2..efdc796e 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -671,7 +671,17 @@ class ConversationViewController: BaseViewController { // test menu if true { - let menu = BubbleMenuView(titles: ["Copy", "Delete"]) + + let copyItem = BubbleMenuView.Item(title: "Copy") { + print("copy\n") + } + + let deleteItem = BubbleMenuView.Item(title: "Delete") { + print("delete\n") + } + + let menu = BubbleMenuView(items: [copyItem, deleteItem]) + menu.setTranslatesAutoresizingMaskIntoConstraints(false) view.addSubview(menu) @@ -682,7 +692,13 @@ class ConversationViewController: BaseViewController { } if true { - let menu = BubbleMenuView(titles: ["Copy"]) + + let copyItem = BubbleMenuView.Item(title: "Copy") { + print("copy\n") + } + + let menu = BubbleMenuView(items: [copyItem]) + menu.setTranslatesAutoresizingMaskIntoConstraints(false) view.addSubview(menu) diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index a9bb30ed..19a5a73d 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -10,12 +10,19 @@ import UIKit class BubbleMenuView: UIView { - var titles: [String] + var items: [Item] var buttons = [UIButton]() - init(titles: [String]) { - self.titles = titles + struct Item { + let title: String + let action: () -> Void + } + + init(items: [Item]) { + + self.items = items + super.init(frame: CGRectZero) makeUI() @@ -25,22 +32,36 @@ class BubbleMenuView: UIView { fatalError("init(coder:) has not been implemented") } + // MARK: Actions + + func tapButton(button: UIButton) { + if let index = find(buttons, button) { + let action = items[index].action + action() + } + } + + // MARK: UI + let arrowHeight: CGFloat = 8 let buttonGap: CGFloat = 12 func makeUI() { - //backgroundColor = UIColor.redColor() backgroundColor = UIColor.clearColor() var format = "H:|" - for (index, title) in enumerate(titles) { + for (index, item) in enumerate(items) { let button = UIButton() - //button.backgroundColor = UIColor.blueColor().colorWithAlphaComponent(0.5) - button.setTitle(title, forState: .Normal) + button.setTitleColor(UIColor.whiteColor(), forState: .Normal) + button.setTitleColor(UIColor.lightGrayColor(), forState: .Highlighted) + + button.setTitle(item.title, forState: .Normal) + button.addTarget(self, action: "tapButton:", forControlEvents: .TouchUpInside) + button.setTranslatesAutoresizingMaskIntoConstraints(false) addSubview(button) @@ -56,8 +77,6 @@ class BubbleMenuView: UIView { format += "-|" - //let format = "H:|[label0][label1][label2]|" - var views = [NSObject: AnyObject]() for (index, button) in enumerate(buttons) { @@ -78,11 +97,6 @@ class BubbleMenuView: UIView { } } -// override func intrinsicContentSize() -> CGSize { -// return CGSize(width: 80 * titles.count, height: 80) -// } - - override func drawRect(rect: CGRect) { UIColor.blackColor().colorWithAlphaComponent(0.7).setFill() From e865b5a7c73f63cf5e62d4f1d5d30849a96c95cc Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 14:30:45 +0800 Subject: [PATCH 03/16] cell longPress show menu --- .../ConversationViewController.swift | 103 ++++++++++++++++++ .../ChatRightText/ChatRightTextCell.swift | 29 +++-- Yep/Views/TextViews/ChatTextView.swift | 8 +- 3 files changed, 125 insertions(+), 15 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index efdc796e..e264f7d7 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -668,6 +668,7 @@ class ConversationViewController: BaseViewController { self.setNeedsStatusBarAppearanceUpdate() + /* // test menu if true { @@ -707,6 +708,7 @@ class ConversationViewController: BaseViewController { NSLayoutConstraint.activateConstraints([menuCenterY, menuCenterX]) } + */ } private func markMessageAsReaded(message: Message) { @@ -2102,6 +2104,106 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } }, collectionView: collectionView, indexPath: indexPath) + cell.longPressAction = { [weak self] cell in + + if let strongSelf = self { + + let copyItem = BubbleMenuView.Item(title: "Copy") { + print("copy\n") + + UIPasteboard.generalPasteboard().string = cell.textContentTextView.text + } + + let deleteItem = BubbleMenuView.Item(title: "Delete") { + print("delete\n") + + dispatch_async(dispatch_get_main_queue()) { + if let strongSelf = self, realm = message.realm { + + var sectionDateMessage: Message? + + if let currentMessageIndex = strongSelf.messages.indexOf(message) { + + let previousMessageIndex = currentMessageIndex - 1 + + if let previousMessage = strongSelf.messages[safe: previousMessageIndex] { + + if previousMessage.mediaType == MessageMediaType.SectionDate.rawValue { + sectionDateMessage = previousMessage + } + } + } + + let currentIndexPath: NSIndexPath + if let index = strongSelf.messages.indexOf(message) { + currentIndexPath = NSIndexPath(forItem: index - strongSelf.displayedMessagesRange.location, inSection: indexPath.section) + } else { + currentIndexPath = indexPath + } + + if let sectionDateMessage = sectionDateMessage { + + var canDeleteTwoMessages = false // 考虑刚好的边界情况,例如消息为本束的最后一条,而 sectionDate 在上一束中 + if strongSelf.displayedMessagesRange.length >= 2 { + strongSelf.displayedMessagesRange.length -= 2 + canDeleteTwoMessages = true + + } else { + if strongSelf.displayedMessagesRange.location >= 1 { + strongSelf.displayedMessagesRange.location -= 1 + } + strongSelf.displayedMessagesRange.length -= 1 + } + + realm.write { + if let mediaMetaData = sectionDateMessage.mediaMetaData { + realm.delete(mediaMetaData) + } + if let mediaMetaData = message.mediaMetaData { + realm.delete(mediaMetaData) + } + realm.delete(sectionDateMessage) + realm.delete(message) + } + + if canDeleteTwoMessages { + let previousIndexPath = NSIndexPath(forItem: currentIndexPath.item - 1, inSection: currentIndexPath.section) + strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([previousIndexPath, currentIndexPath]) + } else { + strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) + } + + } else { + strongSelf.displayedMessagesRange.length -= 1 + realm.write { + if let mediaMetaData = message.mediaMetaData { + realm.delete(mediaMetaData) + } + realm.delete(message) + } + strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) + } + + // 必须更新,插入时需要 + strongSelf.lastTimeMessagesCount = strongSelf.messages.count + } + } + } + + let menu = BubbleMenuView(items: [copyItem, deleteItem]) + + menu.setTranslatesAutoresizingMaskIntoConstraints(false) + + strongSelf.view.addSubview(menu) + + let menuCenterY = NSLayoutConstraint(item: menu, attribute: .CenterY, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: 0) + let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: 0) + + NSLayoutConstraint.activateConstraints([menuCenterY, menuCenterX]) + } + } + + /* cell.deleteMessageAction = { [weak self] in dispatch_async(dispatch_get_main_queue()) { if let strongSelf = self, realm = message.realm { @@ -2175,6 +2277,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } } } + */ return cell } diff --git a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift index 15641756..156b559a 100644 --- a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift +++ b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift @@ -22,10 +22,13 @@ class ChatRightTextCell: ChatRightBaseCell { @IBOutlet weak var textContentTextViewLeadingConstraint: NSLayoutConstraint! @IBOutlet weak var textContentTextViewWidthConstraint: NSLayoutConstraint! - var deleteMessageAction: (() -> Void)? typealias MediaTapAction = () -> Void var mediaTapAction: MediaTapAction? + + var longPressAction: (ChatRightTextCell -> Void)? + //var deleteMessageAction: (() -> Void)? + override func awakeFromNib() { super.awakeFromNib() @@ -43,11 +46,11 @@ class ChatRightTextCell: ChatRightBaseCell { NSUnderlineStyleAttributeName: NSNumber(integer: NSUnderlineStyle.StyleSingle.rawValue), ] - textContentTextView.deleteEnabled = true - textContentTextView.deleteAction = { [weak self] in - println("delete text message?") - self?.deleteMessageAction?() - } +// textContentTextView.deleteEnabled = true +// textContentTextView.deleteAction = { [weak self] in +// println("delete text message?") +// self?.deleteMessageAction?() +// } let longPress = UILongPressGestureRecognizer(target: self, action: "handleLongPress:") textContentTextView.addGestureRecognizer(longPress) @@ -65,13 +68,15 @@ class ChatRightTextCell: ChatRightBaseCell { func handleLongPress(longPress: UILongPressGestureRecognizer) { if longPress.state == .Began { - if let view = longPress.view, superview = view.superview { - view.becomeFirstResponder() +// if let view = longPress.view, superview = view.superview { +// view.becomeFirstResponder() +// +// let menu = UIMenuController.sharedMenuController() +// menu.setTargetRect(view.frame, inView: superview) +// menu.setMenuVisible(true, animated: true) +// } - let menu = UIMenuController.sharedMenuController() - menu.setTargetRect(view.frame, inView: superview) - menu.setMenuVisible(true, animated: true) - } + longPressAction?(self) } } diff --git a/Yep/Views/TextViews/ChatTextView.swift b/Yep/Views/TextViews/ChatTextView.swift index f81fcd8e..9f44ffd6 100644 --- a/Yep/Views/TextViews/ChatTextView.swift +++ b/Yep/Views/TextViews/ChatTextView.swift @@ -10,10 +10,11 @@ import UIKit class ChatTextView: UITextView { -// override func canBecomeFirstResponder() -> Bool { -// return false -// } + override func canBecomeFirstResponder() -> Bool { + return false + } + /* var deleteEnabled = false var deleteAction: (() -> Void)? @@ -32,4 +33,5 @@ class ChatTextView: UITextView { return action == Selector("copy:") } } + */ } From de3c3150325c34e346664420cbbe4c62a2bcf41a Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 14:34:15 +0800 Subject: [PATCH 04/16] hide logic --- .../Conversation/ConversationViewController.swift | 8 ++++++-- Yep/Views/BubbleMenu/BubbleMenuView.swift | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index e264f7d7..817bd24b 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -2108,13 +2108,15 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi if let strongSelf = self { - let copyItem = BubbleMenuView.Item(title: "Copy") { + let copyItem = BubbleMenuView.Item(title: "Copy") { bubbleMenuView in print("copy\n") UIPasteboard.generalPasteboard().string = cell.textContentTextView.text + + bubbleMenuView.hide() } - let deleteItem = BubbleMenuView.Item(title: "Delete") { + let deleteItem = BubbleMenuView.Item(title: "Delete") { bubbleMenuView in print("delete\n") dispatch_async(dispatch_get_main_queue()) { @@ -2188,6 +2190,8 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi strongSelf.lastTimeMessagesCount = strongSelf.messages.count } } + + bubbleMenuView.hide() } let menu = BubbleMenuView(items: [copyItem, deleteItem]) diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index 19a5a73d..6f1f6b63 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -16,7 +16,7 @@ class BubbleMenuView: UIView { struct Item { let title: String - let action: () -> Void + let action: BubbleMenuView -> Void } init(items: [Item]) { @@ -37,10 +37,14 @@ class BubbleMenuView: UIView { func tapButton(button: UIButton) { if let index = find(buttons, button) { let action = items[index].action - action() + action(self) } } + func hide() { + removeFromSuperview() + } + // MARK: UI let arrowHeight: CGFloat = 8 From 12676b4345927f9b2c8c7387d0536ed61ee9bf1c Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 14:35:29 +0800 Subject: [PATCH 05/16] local string --- .../Conversation/ConversationViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 817bd24b..0305a14b 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -2108,7 +2108,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi if let strongSelf = self { - let copyItem = BubbleMenuView.Item(title: "Copy") { bubbleMenuView in + let copyItem = BubbleMenuView.Item(title: NSLocalizedString("Copy", comment: "")) { bubbleMenuView in print("copy\n") UIPasteboard.generalPasteboard().string = cell.textContentTextView.text @@ -2116,7 +2116,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi bubbleMenuView.hide() } - let deleteItem = BubbleMenuView.Item(title: "Delete") { bubbleMenuView in + let deleteItem = BubbleMenuView.Item(title: NSLocalizedString("Delete", comment: "")) { bubbleMenuView in print("delete\n") dispatch_async(dispatch_get_main_queue()) { From d2a58061b8d1c57da637d1ad71c465f3a98dbc71 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 14:52:02 +0800 Subject: [PATCH 06/16] menu position --- .../ConversationViewController.swift | 20 +++++++++++++------ Yep/Views/BubbleMenu/BubbleMenuView.swift | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 0305a14b..bf7f220e 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -2108,15 +2108,15 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi if let strongSelf = self { - let copyItem = BubbleMenuView.Item(title: NSLocalizedString("Copy", comment: "")) { bubbleMenuView in + let copyItem = BubbleMenuView.Item(title: NSLocalizedString("Copy", comment: "")) { menu in print("copy\n") UIPasteboard.generalPasteboard().string = cell.textContentTextView.text - bubbleMenuView.hide() + menu.hide() } - let deleteItem = BubbleMenuView.Item(title: NSLocalizedString("Delete", comment: "")) { bubbleMenuView in + let deleteItem = BubbleMenuView.Item(title: NSLocalizedString("Delete", comment: "")) { menu in print("delete\n") dispatch_async(dispatch_get_main_queue()) { @@ -2191,7 +2191,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } } - bubbleMenuView.hide() + menu.hide() } let menu = BubbleMenuView(items: [copyItem, deleteItem]) @@ -2200,8 +2200,16 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi strongSelf.view.addSubview(menu) - let menuCenterY = NSLayoutConstraint(item: menu, attribute: .CenterY, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: 0) - let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: 0) + let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) + + var centerYConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(strongSelf.conversationCollectionView.frame) + centerYConstant -= CGRectGetHeight(textViewFrame) - menu.offsetY + + let menuCenterY = NSLayoutConstraint(item: menu, attribute: .CenterY, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: centerYConstant) + + let centerXConstant = CGRectGetMidX(textViewFrame) - CGRectGetMidX(strongSelf.conversationCollectionView.frame) + + let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) NSLayoutConstraint.activateConstraints([menuCenterY, menuCenterX]) } diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index 6f1f6b63..0b83ad18 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -49,6 +49,7 @@ class BubbleMenuView: UIView { let arrowHeight: CGFloat = 8 let buttonGap: CGFloat = 12 + let offsetY: CGFloat = 8 func makeUI() { From 3a546c8adca7cf2298b33ac6e481bcbd300bc48e Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 15:32:13 +0800 Subject: [PATCH 07/16] ArrowDirection --- .../ConversationViewController.swift | 27 +++++-- Yep/Views/BubbleMenu/BubbleMenuView.swift | 78 +++++++++++++++---- 2 files changed, 83 insertions(+), 22 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index bf7f220e..aaa97bc9 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -2194,24 +2194,39 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi menu.hide() } - let menu = BubbleMenuView(items: [copyItem, deleteItem]) + let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) + + let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < 64 + 80 ? .Up : .Down + + let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem, deleteItem]) menu.setTranslatesAutoresizingMaskIntoConstraints(false) strongSelf.view.addSubview(menu) - let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) - var centerYConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(strongSelf.conversationCollectionView.frame) - centerYConstant -= CGRectGetHeight(textViewFrame) - menu.offsetY + var vConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(strongSelf.conversationCollectionView.frame) - let menuCenterY = NSLayoutConstraint(item: menu, attribute: .CenterY, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: centerYConstant) + let menuV: NSLayoutConstraint + + switch arrowDirection { + + case .Up: + vConstant += ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV + + menuV = NSLayoutConstraint(item: menu, attribute: .Top, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) + + case .Down: + vConstant -= ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV + + menuV = NSLayoutConstraint(item: menu, attribute: .Bottom, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) + } let centerXConstant = CGRectGetMidX(textViewFrame) - CGRectGetMidX(strongSelf.conversationCollectionView.frame) let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) - NSLayoutConstraint.activateConstraints([menuCenterY, menuCenterX]) + NSLayoutConstraint.activateConstraints([menuV, menuCenterX]) } } diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index 0b83ad18..5c36bbeb 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -10,17 +10,24 @@ import UIKit class BubbleMenuView: UIView { - var items: [Item] - - var buttons = [UIButton]() + enum ArrowDirection { + case Up + case Down + } struct Item { let title: String let action: BubbleMenuView -> Void } - init(items: [Item]) { + var arrowDirection: ArrowDirection + var items: [Item] + var buttons = [UIButton]() + + init(arrowDirection: ArrowDirection, items: [Item]) { + + self.arrowDirection = arrowDirection self.items = items super.init(frame: CGRectZero) @@ -49,7 +56,7 @@ class BubbleMenuView: UIView { let arrowHeight: CGFloat = 8 let buttonGap: CGFloat = 12 - let offsetY: CGFloat = 8 + let offsetV: CGFloat = 1 func makeUI() { @@ -96,9 +103,23 @@ class BubbleMenuView: UIView { if let firstButton = buttons.first { let firstButtonTop = NSLayoutConstraint(item: firstButton, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0) - let firstButtonBottom = NSLayoutConstraint(item: firstButton, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1, constant: -arrowHeight) - NSLayoutConstraint.activateConstraints([firstButtonTop, firstButtonBottom]) + switch arrowDirection { + + case .Up: + + let firstButtonTop = NSLayoutConstraint(item: firstButton, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: arrowHeight) + let firstButtonBottom = NSLayoutConstraint(item: firstButton, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1, constant: 0) + + NSLayoutConstraint.activateConstraints([firstButtonTop, firstButtonBottom]) + + case .Down: + + let firstButtonTop = NSLayoutConstraint(item: firstButton, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1, constant: 0) + let firstButtonBottom = NSLayoutConstraint(item: firstButton, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1, constant: -arrowHeight) + + NSLayoutConstraint.activateConstraints([firstButtonTop, firstButtonBottom]) + } } } @@ -109,22 +130,47 @@ class BubbleMenuView: UIView { // bubble var roundedRect = rect - roundedRect.size.height -= arrowHeight + + switch arrowDirection { + + case .Up: + roundedRect.origin.y += arrowHeight + roundedRect.size.height -= arrowHeight + + case .Down: + roundedRect.size.height -= arrowHeight + } + let bubblePath = UIBezierPath(roundedRect: roundedRect, cornerRadius: 5) bubblePath.fill() // arrow - let buttomX = CGRectGetMidX(rect) - let buttomY = CGRectGetMaxY(rect) + switch arrowDirection { - let arrowPath = UIBezierPath() - arrowPath.moveToPoint(CGPointMake(buttomX, buttomY)) - arrowPath.addLineToPoint(CGPointMake(buttomX - (arrowHeight - 1), buttomY - arrowHeight)) - arrowPath.addLineToPoint(CGPointMake(buttomX + (arrowHeight - 1), buttomY - arrowHeight)) - arrowPath.closePath() - arrowPath.fill() + case .Up: + let topX = CGRectGetMidX(rect) + let topY = CGRectGetMinY(rect) + + let arrowPath = UIBezierPath() + arrowPath.moveToPoint(CGPointMake(topX, topY)) + arrowPath.addLineToPoint(CGPointMake(topX - (arrowHeight - 1), topY + arrowHeight)) + arrowPath.addLineToPoint(CGPointMake(topX + (arrowHeight - 1), topY + arrowHeight)) + arrowPath.closePath() + arrowPath.fill() + + case .Down: + let buttomX = CGRectGetMidX(rect) + let buttomY = CGRectGetMaxY(rect) + + let arrowPath = UIBezierPath() + arrowPath.moveToPoint(CGPointMake(buttomX, buttomY)) + arrowPath.addLineToPoint(CGPointMake(buttomX - (arrowHeight - 1), buttomY - arrowHeight)) + arrowPath.addLineToPoint(CGPointMake(buttomX + (arrowHeight - 1), buttomY - arrowHeight)) + arrowPath.closePath() + arrowPath.fill() + } // lines From 69f9060cdfb33674bf64c4e9cc20fe29b7cf7157 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 15:41:18 +0800 Subject: [PATCH 08/16] hide currentMenu when new menu show, vc disappear, or user scroll --- .../ConversationViewController.swift | 32 +++++++++++++------ Yep/Views/BubbleMenu/BubbleMenuView.swift | 2 +- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index aaa97bc9..b2cf7589 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -109,6 +109,8 @@ class ConversationViewController: BaseViewController { @IBOutlet weak var takePhotoButton: MessageTypeButton! @IBOutlet weak var addLocationButton: MessageTypeButton! + var currentMenu: BubbleMenuView? + var originalNavigationControllerDelegate: UINavigationControllerDelegate? var waverView: YepWaverView! @@ -741,6 +743,12 @@ class ConversationViewController: BaseViewController { } } + override func viewWillDisappear(animated: Bool) { + super.viewWillDisappear(animated) + + currentMenu?.hide() + } + override func viewDidDisappear(animated: Bool) { super.viewDidDisappear(animated) @@ -2106,7 +2114,9 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi cell.longPressAction = { [weak self] cell in - if let strongSelf = self { + self?.currentMenu?.hide() + + if let strongSelf = self { let copyItem = BubbleMenuView.Item(title: NSLocalizedString("Copy", comment: "")) { menu in print("copy\n") @@ -2185,7 +2195,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) } - + // 必须更新,插入时需要 strongSelf.lastTimeMessagesCount = strongSelf.messages.count } @@ -2199,7 +2209,9 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < 64 + 80 ? .Up : .Down let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem, deleteItem]) - + + strongSelf.currentMenu = menu + menu.setTranslatesAutoresizingMaskIntoConstraints(false) strongSelf.view.addSubview(menu) @@ -2213,19 +2225,19 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi case .Up: vConstant += ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV - + menuV = NSLayoutConstraint(item: menu, attribute: .Top, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) - + case .Down: vConstant -= ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV - + menuV = NSLayoutConstraint(item: menu, attribute: .Bottom, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) } - + let centerXConstant = CGRectGetMidX(textViewFrame) - CGRectGetMidX(strongSelf.conversationCollectionView.frame) - + let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) - + NSLayoutConstraint.activateConstraints([menuV, menuCenterX]) } } @@ -2355,6 +2367,8 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi func scrollViewDidScroll(scrollView: UIScrollView) { pullToRefreshView.scrollViewDidScroll(scrollView) + + currentMenu?.hide() } func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index 5c36bbeb..4f439eb1 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -56,7 +56,7 @@ class BubbleMenuView: UIView { let arrowHeight: CGFloat = 8 let buttonGap: CGFloat = 12 - let offsetV: CGFloat = 1 + let offsetV: CGFloat = 2 func makeUI() { From 009bc18bde40275fcce4eca707633957c294d439 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 16:01:07 +0800 Subject: [PATCH 09/16] longPressAction for ChatLeftTextCell show menu --- .../ConversationViewController.swift | 52 +++++++++++++++++++ .../Cells/ChatLeftText/ChatLeftTextCell.swift | 20 ++++--- 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index b2cf7589..8e625a14 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -1935,6 +1935,58 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi cell.configureWithMessage(message, textContentLabelWidth: textContentLabelWidthOfMessage(message), collectionView: collectionView, indexPath: indexPath) + cell.longPressAction = { [weak self] cell in + + self?.currentMenu?.hide() + + if let strongSelf = self { + + let copyItem = BubbleMenuView.Item(title: NSLocalizedString("Copy", comment: "")) { menu in + print("copy\n") + + UIPasteboard.generalPasteboard().string = cell.textContentTextView.text + + menu.hide() + } + + let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) + + let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < 64 + 80 ? .Up : .Down + + let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem]) + + strongSelf.currentMenu = menu + + menu.setTranslatesAutoresizingMaskIntoConstraints(false) + + strongSelf.view.addSubview(menu) + + + var vConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(strongSelf.conversationCollectionView.frame) + + let menuV: NSLayoutConstraint + + switch arrowDirection { + + case .Up: + vConstant += ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV + + menuV = NSLayoutConstraint(item: menu, attribute: .Top, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) + + case .Down: + vConstant -= ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV + + menuV = NSLayoutConstraint(item: menu, attribute: .Bottom, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) + } + + let centerXConstant = CGRectGetMidX(textViewFrame) - CGRectGetMidX(strongSelf.conversationCollectionView.frame) + + let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) + + NSLayoutConstraint.activateConstraints([menuV, menuCenterX]) + } + } + return cell } diff --git a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift index de7f7919..66467118 100644 --- a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift +++ b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift @@ -22,6 +22,8 @@ class ChatLeftTextCell: UICollectionViewCell { @IBOutlet weak var textContentTextViewLeadingConstraint: NSLayoutConstraint! @IBOutlet weak var textContentTextViewWidthConstraint: NSLayoutConstraint! + var longPressAction: (ChatLeftTextCell -> Void)? + override func awakeFromNib() { super.awakeFromNib() @@ -58,15 +60,17 @@ class ChatLeftTextCell: UICollectionViewCell { } func handleLongPress(longPress: UILongPressGestureRecognizer) { - if longPress.state == .Began { - if let view = longPress.view, superview = view.superview { - view.becomeFirstResponder() +// if longPress.state == .Began { +// if let view = longPress.view, superview = view.superview { +// view.becomeFirstResponder() +// +// let menu = UIMenuController.sharedMenuController() +// menu.setTargetRect(view.frame, inView: superview) +// menu.setMenuVisible(true, animated: true) +// } +// } - let menu = UIMenuController.sharedMenuController() - menu.setTargetRect(view.frame, inView: superview) - menu.setMenuVisible(true, animated: true) - } - } + longPressAction?(self) } func configureWithMessage(message: Message, textContentLabelWidth: CGFloat, collectionView: UICollectionView, indexPath: NSIndexPath) { From 435519d49615132952522695e58c1dbf274d55e3 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 16:09:22 +0800 Subject: [PATCH 10/16] refactor show BubbleMenuView --- .../ConversationViewController.swift | 56 +------------------ Yep/Views/BubbleMenu/BubbleMenuView.swift | 29 ++++++++++ 2 files changed, 31 insertions(+), 54 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 8e625a14..7cc7a0e2 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -1957,33 +1957,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi strongSelf.currentMenu = menu - menu.setTranslatesAutoresizingMaskIntoConstraints(false) - - strongSelf.view.addSubview(menu) - - - var vConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(strongSelf.conversationCollectionView.frame) - - let menuV: NSLayoutConstraint - - switch arrowDirection { - - case .Up: - vConstant += ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV - - menuV = NSLayoutConstraint(item: menu, attribute: .Top, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) - - case .Down: - vConstant -= ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV - - menuV = NSLayoutConstraint(item: menu, attribute: .Bottom, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) - } - - let centerXConstant = CGRectGetMidX(textViewFrame) - CGRectGetMidX(strongSelf.conversationCollectionView.frame) - - let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) - - NSLayoutConstraint.activateConstraints([menuV, menuCenterX]) + menu.showInView(strongSelf.view, withTextViewFrame: textViewFrame) } } @@ -2264,33 +2238,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi strongSelf.currentMenu = menu - menu.setTranslatesAutoresizingMaskIntoConstraints(false) - - strongSelf.view.addSubview(menu) - - - var vConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(strongSelf.conversationCollectionView.frame) - - let menuV: NSLayoutConstraint - - switch arrowDirection { - - case .Up: - vConstant += ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV - - menuV = NSLayoutConstraint(item: menu, attribute: .Top, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) - - case .Down: - vConstant -= ceil(CGRectGetHeight(textViewFrame) * 0.5) - menu.offsetV - - menuV = NSLayoutConstraint(item: menu, attribute: .Bottom, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterY, multiplier: 1, constant: vConstant) - } - - let centerXConstant = CGRectGetMidX(textViewFrame) - CGRectGetMidX(strongSelf.conversationCollectionView.frame) - - let menuCenterX = NSLayoutConstraint(item: menu, attribute: .CenterX, relatedBy: .Equal, toItem: strongSelf.view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) - - NSLayoutConstraint.activateConstraints([menuV, menuCenterX]) + menu.showInView(strongSelf.view, withTextViewFrame: textViewFrame) } } diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index 4f439eb1..f5251986 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -48,6 +48,35 @@ class BubbleMenuView: UIView { } } + func showInView(view: UIView, withTextViewFrame textViewFrame: CGRect) { + + setTranslatesAutoresizingMaskIntoConstraints(false) + view.addSubview(self) + + var vConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(view.frame) + + let menuV: NSLayoutConstraint + + switch arrowDirection { + + case .Up: + vConstant += ceil(CGRectGetHeight(textViewFrame) * 0.5) - offsetV + + menuV = NSLayoutConstraint(item: self, attribute: .Top, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: vConstant) + + case .Down: + vConstant -= ceil(CGRectGetHeight(textViewFrame) * 0.5) - offsetV + + menuV = NSLayoutConstraint(item: self, attribute: .Bottom, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: vConstant) + } + + let centerXConstant = CGRectGetMidX(textViewFrame) - CGRectGetMidX(view.frame) + + let menuCenterX = NSLayoutConstraint(item: self, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) + + NSLayoutConstraint.activateConstraints([menuV, menuCenterX]) + } + func hide() { removeFromSuperview() } From 1934a5858c06471c2af16efb7e8af69d894c398a Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 16:12:17 +0800 Subject: [PATCH 11/16] clean code --- .../ConversationViewController.swift | 76 ------------------- .../Cells/ChatLeftText/ChatLeftTextCell.swift | 23 +----- .../ChatRightText/ChatRightTextCell.swift | 16 ---- Yep/Views/TextViews/ChatTextView.swift | 21 ----- 4 files changed, 3 insertions(+), 133 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 7cc7a0e2..15b51a04 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -2242,82 +2242,6 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } } - /* - cell.deleteMessageAction = { [weak self] in - dispatch_async(dispatch_get_main_queue()) { - if let strongSelf = self, realm = message.realm { - - var sectionDateMessage: Message? - - if let currentMessageIndex = strongSelf.messages.indexOf(message) { - - let previousMessageIndex = currentMessageIndex - 1 - - if let previousMessage = strongSelf.messages[safe: previousMessageIndex] { - - if previousMessage.mediaType == MessageMediaType.SectionDate.rawValue { - sectionDateMessage = previousMessage - } - } - } - - let currentIndexPath: NSIndexPath - if let index = strongSelf.messages.indexOf(message) { - currentIndexPath = NSIndexPath(forItem: index - strongSelf.displayedMessagesRange.location, inSection: indexPath.section) - } else { - currentIndexPath = indexPath - } - - if let sectionDateMessage = sectionDateMessage { - - var canDeleteTwoMessages = false // 考虑刚好的边界情况,例如消息为本束的最后一条,而 sectionDate 在上一束中 - if strongSelf.displayedMessagesRange.length >= 2 { - strongSelf.displayedMessagesRange.length -= 2 - canDeleteTwoMessages = true - - } else { - if strongSelf.displayedMessagesRange.location >= 1 { - strongSelf.displayedMessagesRange.location -= 1 - } - strongSelf.displayedMessagesRange.length -= 1 - } - - realm.write { - if let mediaMetaData = sectionDateMessage.mediaMetaData { - realm.delete(mediaMetaData) - } - if let mediaMetaData = message.mediaMetaData { - realm.delete(mediaMetaData) - } - realm.delete(sectionDateMessage) - realm.delete(message) - } - - if canDeleteTwoMessages { - let previousIndexPath = NSIndexPath(forItem: currentIndexPath.item - 1, inSection: currentIndexPath.section) - strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([previousIndexPath, currentIndexPath]) - } else { - strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) - } - - } else { - strongSelf.displayedMessagesRange.length -= 1 - realm.write { - if let mediaMetaData = message.mediaMetaData { - realm.delete(mediaMetaData) - } - realm.delete(message) - } - strongSelf.conversationCollectionView.deleteItemsAtIndexPaths([currentIndexPath]) - } - - // 必须更新,插入时需要 - strongSelf.lastTimeMessagesCount = strongSelf.messages.count - } - } - } - */ - return cell } } diff --git a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift index 66467118..9cb14931 100644 --- a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift +++ b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift @@ -40,15 +40,6 @@ class ChatLeftTextCell: UICollectionViewCell { NSUnderlineStyleAttributeName: NSNumber(integer: NSUnderlineStyle.StyleSingle.rawValue), ] -// textContentTextView.editable = false -// if let gestureRecognizers = textContentTextView.gestureRecognizers as? [UIGestureRecognizer] { -// for recognizer in gestureRecognizers { -// if recognizer.isKindOfClass(UILongPressGestureRecognizer.self) { -// recognizer.enabled = false -// } -// } -// } - let longPress = UILongPressGestureRecognizer(target: self, action: "handleLongPress:") textContentTextView.addGestureRecognizer(longPress) @@ -60,17 +51,9 @@ class ChatLeftTextCell: UICollectionViewCell { } func handleLongPress(longPress: UILongPressGestureRecognizer) { -// if longPress.state == .Began { -// if let view = longPress.view, superview = view.superview { -// view.becomeFirstResponder() -// -// let menu = UIMenuController.sharedMenuController() -// menu.setTargetRect(view.frame, inView: superview) -// menu.setMenuVisible(true, animated: true) -// } -// } - - longPressAction?(self) + if longPress.state == .Began { + longPressAction?(self) + } } func configureWithMessage(message: Message, textContentLabelWidth: CGFloat, collectionView: UICollectionView, indexPath: NSIndexPath) { diff --git a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift index 156b559a..66e9bf20 100644 --- a/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift +++ b/Yep/Views/Cells/ChatRightText/ChatRightTextCell.swift @@ -25,9 +25,7 @@ class ChatRightTextCell: ChatRightBaseCell { typealias MediaTapAction = () -> Void var mediaTapAction: MediaTapAction? - var longPressAction: (ChatRightTextCell -> Void)? - //var deleteMessageAction: (() -> Void)? override func awakeFromNib() { super.awakeFromNib() @@ -46,12 +44,6 @@ class ChatRightTextCell: ChatRightBaseCell { NSUnderlineStyleAttributeName: NSNumber(integer: NSUnderlineStyle.StyleSingle.rawValue), ] -// textContentTextView.deleteEnabled = true -// textContentTextView.deleteAction = { [weak self] in -// println("delete text message?") -// self?.deleteMessageAction?() -// } - let longPress = UILongPressGestureRecognizer(target: self, action: "handleLongPress:") textContentTextView.addGestureRecognizer(longPress) @@ -68,14 +60,6 @@ class ChatRightTextCell: ChatRightBaseCell { func handleLongPress(longPress: UILongPressGestureRecognizer) { if longPress.state == .Began { -// if let view = longPress.view, superview = view.superview { -// view.becomeFirstResponder() -// -// let menu = UIMenuController.sharedMenuController() -// menu.setTargetRect(view.frame, inView: superview) -// menu.setMenuVisible(true, animated: true) -// } - longPressAction?(self) } } diff --git a/Yep/Views/TextViews/ChatTextView.swift b/Yep/Views/TextViews/ChatTextView.swift index 9f44ffd6..c9b44672 100644 --- a/Yep/Views/TextViews/ChatTextView.swift +++ b/Yep/Views/TextViews/ChatTextView.swift @@ -13,25 +13,4 @@ class ChatTextView: UITextView { override func canBecomeFirstResponder() -> Bool { return false } - - /* - var deleteEnabled = false - var deleteAction: (() -> Void)? - - override func copy(sender: AnyObject?) { - UIPasteboard.generalPasteboard().string = text - } - - override func delete(sender: AnyObject?) { - deleteAction?() - } - - override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool { - if deleteEnabled { - return action == Selector("copy:") || action == Selector("delete:") - } else { - return action == Selector("copy:") - } - } - */ } From 39831795193e1cc0afe4f56972caa881588faa88 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 16:18:30 +0800 Subject: [PATCH 12/16] use menuDirectionUpThreshold --- Yep/Configs/YepConfig.swift | 4 ++++ .../Conversation/ConversationViewController.swift | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Yep/Configs/YepConfig.swift b/Yep/Configs/YepConfig.swift index c7431915..735b9801 100644 --- a/Yep/Configs/YepConfig.swift +++ b/Yep/Configs/YepConfig.swift @@ -81,6 +81,10 @@ class YepConfig { return 100 } + struct Conversation { + static let menuDirectionUpThreshold: CGFloat = 64 + 60 + } + struct AudioRecord { static let shortestDuration: NSTimeInterval = 0.5 static let longestDuration: NSTimeInterval = 60 diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 15b51a04..245026e3 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -1951,7 +1951,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) - let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < 64 + 80 ? .Up : .Down + let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < YepConfig.Conversation.menuDirectionUpThreshold ? .Up : .Down let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem]) @@ -2232,7 +2232,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) - let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < 64 + 80 ? .Up : .Down + let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < YepConfig.Conversation.menuDirectionUpThreshold ? .Up : .Down let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem, deleteItem]) From 25ed49bd26e73e25b68fcd27da642b21974d82f0 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 16:30:44 +0800 Subject: [PATCH 13/16] show / hide animation --- Yep/Views/BubbleMenu/BubbleMenuView.swift | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index f5251986..17e5794f 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -50,6 +50,8 @@ class BubbleMenuView: UIView { func showInView(view: UIView, withTextViewFrame textViewFrame: CGRect) { + // position + setTranslatesAutoresizingMaskIntoConstraints(false) view.addSubview(self) @@ -75,16 +77,33 @@ class BubbleMenuView: UIView { let menuCenterX = NSLayoutConstraint(item: self, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) NSLayoutConstraint.activateConstraints([menuV, menuCenterX]) + + + // animation + + transform = CGAffineTransformMakeScale(0.0001, 0.0001) + + UIView.animateWithDuration(0.25, delay: 0.0, usingSpringWithDamping: 0.65, initialSpringVelocity: 0.0, options: UIViewAnimationOptions(0), animations: { _ in + self.transform = CGAffineTransformMakeScale(1.0, 1.0) + }, completion: { finished in + self.transform = CGAffineTransformIdentity + }) } func hide() { - removeFromSuperview() + + UIView.animateWithDuration(0.1, delay: 0.0, options: .CurveEaseInOut, animations: { _ in + self.transform = CGAffineTransformMakeScale(0.0001, 0.0001) + + }, completion: { finished in + self.removeFromSuperview() + }) } // MARK: UI let arrowHeight: CGFloat = 8 - let buttonGap: CGFloat = 12 + let buttonGap: CGFloat = 16 let offsetV: CGFloat = 2 func makeUI() { From 0451f27181d7748207945255b380d7f48e1a3274 Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 16:45:54 +0800 Subject: [PATCH 14/16] better removeOldMenu logic --- .../ConversationViewController.swift | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 245026e3..2550c8a3 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -111,6 +111,11 @@ class ConversationViewController: BaseViewController { var currentMenu: BubbleMenuView? + func removeOldMenu() { + currentMenu?.hide() + currentMenu = nil + } + var originalNavigationControllerDelegate: UINavigationControllerDelegate? var waverView: YepWaverView! @@ -527,6 +532,8 @@ class ConversationViewController: BaseViewController { messageToolbar.stateTransitionAction = { [weak self] (messageToolbar, previousState, currentState) in + self?.removeOldMenu() + if let strongSelf = self { switch (previousState, currentState) { @@ -746,7 +753,7 @@ class ConversationViewController: BaseViewController { override func viewWillDisappear(animated: Bool) { super.viewWillDisappear(animated) - currentMenu?.hide() + removeOldMenu() } override func viewDidDisappear(animated: Bool) { @@ -1020,6 +1027,8 @@ class ConversationViewController: BaseViewController { func moreAction() { + removeOldMenu() + messageToolbar.state = .Default moreView.showProfileAction = { [weak self] in @@ -1937,7 +1946,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi cell.longPressAction = { [weak self] cell in - self?.currentMenu?.hide() + self?.removeOldMenu() if let strongSelf = self { @@ -1947,6 +1956,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi UIPasteboard.generalPasteboard().string = cell.textContentTextView.text menu.hide() + self?.currentMenu = nil } let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) @@ -2140,7 +2150,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi cell.longPressAction = { [weak self] cell in - self?.currentMenu?.hide() + self?.removeOldMenu() if let strongSelf = self { @@ -2150,6 +2160,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi UIPasteboard.generalPasteboard().string = cell.textContentTextView.text menu.hide() + self?.currentMenu = nil } let deleteItem = BubbleMenuView.Item(title: NSLocalizedString("Delete", comment: "")) { menu in @@ -2228,6 +2239,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } menu.hide() + self?.currentMenu = nil } let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) @@ -2292,7 +2304,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi func scrollViewDidScroll(scrollView: UIScrollView) { pullToRefreshView.scrollViewDidScroll(scrollView) - currentMenu?.hide() + removeOldMenu() } func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { From d6dd86b7c195c2622c8731ee4a91f5ae2f72fa0f Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 17:08:04 +0800 Subject: [PATCH 15/16] BubbleMenuView Item Type --- .../ConversationViewController.swift | 8 ++++-- Yep/Views/BubbleMenu/BubbleMenuView.swift | 28 ++++++++++++++++--- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 2550c8a3..97907d97 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -1860,6 +1860,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi markMessageAsReaded(message) switch message.mediaType { + case MessageMediaType.Image.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatLeftImageCellIdentifier, forIndexPath: indexPath) as! ChatLeftImageCell @@ -1950,7 +1951,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi if let strongSelf = self { - let copyItem = BubbleMenuView.Item(title: NSLocalizedString("Copy", comment: "")) { menu in + let copyItem = BubbleMenuView.Item(type: .Normal, title: NSLocalizedString("Copy", comment: "")) { menu in print("copy\n") UIPasteboard.generalPasteboard().string = cell.textContentTextView.text @@ -1977,6 +1978,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi } else { // from Me switch message.mediaType { + case MessageMediaType.Image.rawValue: let cell = collectionView.dequeueReusableCellWithReuseIdentifier(chatRightImageCellIdentifier, forIndexPath: indexPath) as! ChatRightImageCell @@ -2154,7 +2156,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi if let strongSelf = self { - let copyItem = BubbleMenuView.Item(title: NSLocalizedString("Copy", comment: "")) { menu in + let copyItem = BubbleMenuView.Item(type: .Normal, title: NSLocalizedString("Copy", comment: "")) { menu in print("copy\n") UIPasteboard.generalPasteboard().string = cell.textContentTextView.text @@ -2163,7 +2165,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi self?.currentMenu = nil } - let deleteItem = BubbleMenuView.Item(title: NSLocalizedString("Delete", comment: "")) { menu in + let deleteItem = BubbleMenuView.Item(type: .Danger, title: NSLocalizedString("Delete", comment: "")) { menu in print("delete\n") dispatch_async(dispatch_get_main_queue()) { diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index 17e5794f..175927c0 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -16,7 +16,15 @@ class BubbleMenuView: UIView { } struct Item { + + enum Type { + case Normal + case Danger + } + let type: Type + let title: String + let action: BubbleMenuView -> Void } @@ -104,7 +112,7 @@ class BubbleMenuView: UIView { let arrowHeight: CGFloat = 8 let buttonGap: CGFloat = 16 - let offsetV: CGFloat = 2 + let offsetV: CGFloat = 1 func makeUI() { @@ -116,8 +124,20 @@ class BubbleMenuView: UIView { let button = UIButton() - button.setTitleColor(UIColor.whiteColor(), forState: .Normal) - button.setTitleColor(UIColor.lightGrayColor(), forState: .Highlighted) + switch item.type { + + case .Normal: + + button.setTitleColor(UIColor.whiteColor(), forState: .Normal) + button.setTitleColor(UIColor.lightGrayColor(), forState: .Highlighted) + + case .Danger: + + let dangerRed = UIColor(red: 1, green: 0.18, blue: 0.40, alpha: 1) + + button.setTitleColor(dangerRed, forState: .Normal) + button.setTitleColor(dangerRed.colorWithAlphaComponent(0.3), forState: .Highlighted) + } button.setTitle(item.title, forState: .Normal) button.addTarget(self, action: "tapButton:", forControlEvents: .TouchUpInside) @@ -173,7 +193,7 @@ class BubbleMenuView: UIView { override func drawRect(rect: CGRect) { - UIColor.blackColor().colorWithAlphaComponent(0.7).setFill() + UIColor.blackColor().colorWithAlphaComponent(0.6).setFill() // bubble From 6badf46e6418935d0b8df78b259257c324c82acf Mon Sep 17 00:00:00 2001 From: nixzhu Date: Thu, 23 Jul 2015 17:28:45 +0800 Subject: [PATCH 16/16] use bubbleFrame to show menu --- .../Conversation/ConversationViewController.swift | 12 ++++++------ Yep/Views/BubbleMenu/BubbleMenuView.swift | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index 97907d97..d284208a 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -1960,15 +1960,15 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi self?.currentMenu = nil } - let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) + let bubbleFrame = cell.convertRect(cell.bubbleBodyImageView.frame, toView: strongSelf.view) - let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < YepConfig.Conversation.menuDirectionUpThreshold ? .Up : .Down + let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(bubbleFrame) < YepConfig.Conversation.menuDirectionUpThreshold ? .Up : .Down let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem]) strongSelf.currentMenu = menu - menu.showInView(strongSelf.view, withTextViewFrame: textViewFrame) + menu.showInView(strongSelf.view, withBubbleFrame: bubbleFrame) } } @@ -2244,15 +2244,15 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi self?.currentMenu = nil } - let textViewFrame = cell.convertRect(cell.textContentTextView.frame, toView: strongSelf.view) + let bubbleFrame = cell.convertRect(cell.bubbleBodyImageView.frame, toView: strongSelf.view) - let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(textViewFrame) < YepConfig.Conversation.menuDirectionUpThreshold ? .Up : .Down + let arrowDirection: BubbleMenuView.ArrowDirection = CGRectGetMidY(bubbleFrame) < YepConfig.Conversation.menuDirectionUpThreshold ? .Up : .Down let menu = BubbleMenuView(arrowDirection: arrowDirection, items: [copyItem, deleteItem]) strongSelf.currentMenu = menu - menu.showInView(strongSelf.view, withTextViewFrame: textViewFrame) + menu.showInView(strongSelf.view, withBubbleFrame: bubbleFrame) } } diff --git a/Yep/Views/BubbleMenu/BubbleMenuView.swift b/Yep/Views/BubbleMenu/BubbleMenuView.swift index 175927c0..e4b1b322 100644 --- a/Yep/Views/BubbleMenu/BubbleMenuView.swift +++ b/Yep/Views/BubbleMenu/BubbleMenuView.swift @@ -56,31 +56,31 @@ class BubbleMenuView: UIView { } } - func showInView(view: UIView, withTextViewFrame textViewFrame: CGRect) { + func showInView(view: UIView, withBubbleFrame bubbleFrame: CGRect) { // position setTranslatesAutoresizingMaskIntoConstraints(false) view.addSubview(self) - var vConstant = CGRectGetMidY(textViewFrame) - CGRectGetMidY(view.frame) + var vConstant = CGRectGetMidY(bubbleFrame) - CGRectGetMidY(view.frame) let menuV: NSLayoutConstraint switch arrowDirection { case .Up: - vConstant += ceil(CGRectGetHeight(textViewFrame) * 0.5) - offsetV + vConstant += ceil(CGRectGetHeight(bubbleFrame) * 0.5) - offsetV menuV = NSLayoutConstraint(item: self, attribute: .Top, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: vConstant) case .Down: - vConstant -= ceil(CGRectGetHeight(textViewFrame) * 0.5) - offsetV + vConstant -= ceil(CGRectGetHeight(bubbleFrame) * 0.5) - offsetV menuV = NSLayoutConstraint(item: self, attribute: .Bottom, relatedBy: .Equal, toItem: view, attribute: .CenterY, multiplier: 1, constant: vConstant) } - let centerXConstant = CGRectGetMidX(textViewFrame) - CGRectGetMidX(view.frame) + let centerXConstant = CGRectGetMidX(bubbleFrame) - CGRectGetMidX(view.frame) let menuCenterX = NSLayoutConstraint(item: self, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .CenterX, multiplier: 1, constant: centerXConstant) @@ -112,7 +112,7 @@ class BubbleMenuView: UIView { let arrowHeight: CGFloat = 8 let buttonGap: CGFloat = 16 - let offsetV: CGFloat = 1 + let offsetV: CGFloat = -1 func makeUI() { @@ -133,7 +133,7 @@ class BubbleMenuView: UIView { case .Danger: - let dangerRed = UIColor(red: 1, green: 0.18, blue: 0.40, alpha: 1) + let dangerRed = UIColor(red: 1, green: 0.4, blue: 0.4, alpha: 1) button.setTitleColor(dangerRed, forState: .Normal) button.setTitleColor(dangerRed.colorWithAlphaComponent(0.3), forState: .Highlighted)