MKAnnotationView not detecting if button or title touched - mapkit

Hello my problem is that this code:
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control is UIButton {
if (control as! UIButton).buttonType == .DetailDisclosure{removeAnnotation()}
else{performSegueWithIdentifier("edit", sender: nil)}
}
}
seems not to work as it should. The problem is that removeAnnotation() is called always even when I touch title, not the button. How can I fix that?

Add the info right button in the
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
// add button here, i.e.
let btn = UIButton(type: .Custom)
btn.frame = CGRectMake(0, 0, 30, 30)
btn.setImage(UIImage(named: "info"), forState: .Normal)
annotationView.rightCalloutAccessoryView = btn
// ... other required code
}
Then within the
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
print("Tap")
}
}

Related

How to use AVPlayer and Image in UITableViewCell depending upon the response from my API

Functionality : I need to implement a tableview where the cells will have either an image or a video depending upon the category in my API.
Whats happening : The images and video are displayed well but when a cell with video is displayed it replaces all the cell with AVPlayer, the cells with the images too.
Code : -
(in cellForRowAtIndexPath - )
if (![dict[#"video_360x290"] isEqualToString:#""]) {
AVPlayerItem* playerItem = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:dict[#"video_360x290"]]];
AVPlayer *playVideo = [[AVPlayer alloc] initWithPlayerItem:playerItem];
cell.playerViewController = [[AVPlayerViewController alloc] init];
cell.playerViewController.player = playVideo;
cell.playerViewController.player.volume = 10;
cell.playerViewController.view.frame = CGRectMake(0, 0, cell.vPost.frame.size.width, cell.vPost.frame.size.height);
[cell.vPost addSubview:cell.playerViewController.view];
[playVideo play];
}
else{
[cell.iPost sd_setImageWithURL:dict[#"image"] placeholderImage:[UIImage imageNamed:#"imageNotAvailable"] options:SDWebImageHighPriority];
}
What i Need : I need that cell with images displays images and cell with video displays video
Thanks in advance.
Let TableViewCell Class name is ImageVideoCell
Create THREE cells from Storyboard in TableView, 1 for Image and 2 for Video and change cell identifier. For Image Cell change Identifier to "ImageCell" and for Video Cell change Identifier to "VideoCell1" and "VideoCell2" add same tableViewCell Class on all cells like here ImageVideoCell.
And in Controller
class ViewController: UIViewController {
// MARK: - Outlets
#IBOutlet weak var tableView: UITableView!
// MARK: - Properties
var imgVideos = [ImgVideo?]()
var player : AVPlayer?
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
// API call to get Images and videos in TableView
tableView.dataSource = self
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
if player?.isPlaying == true {
self.player?.pause()
self.player = nil
}
}
// MARK: - Action
#IBAction func play_pauseButtonPressed(_ sender: UIButton) {
guard let video = imgVideos[sender.tag] else { return } // get video URl here
guard let cell = tableView.cellForRow(at: IndexPath(row: sender.tag, section: 0)) as? ImageVideoCell else { return }
// if Video is already Playing And User want to Pause it then
if player?.isPlaying ?? false && video.isSelected {
player?.pause()
sender.setImage(#imageLiteral(resourceName: "play-button"), for: .normal)
}
// if the Video is pause and User want to Play it again
else if player?.isPlaying ?? true == false && video.isSelected {
player?.play()
sender.setImage(#imageLiteral(resourceName: "media-pause"), for: .normal)
}
// Play any other Video
else {
for (index, video) in audios.enumerated() {
if video?.isSelected ?? false {
video?.isSelected = false
tableView.beginUpdates()
tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .none)
tableView.endUpdates()
}
}
video.isSelected = true
tableView.beginUpdates()
tableView.reloadRows(at: [IndexPath(row: sender.tag, section: 0)], with: .none)
tableView.endUpdates()
guard let cell = tableView.cellForRow(at: IndexPath(row: sender.tag, section: 0)) as? ImageVideoCell else { return }
cell.play_pauseButton.setImage(#imageLiteral(resourceName: "media-pause"), for: .normal)
play(videoUrl: vedio.url ?? "") // Play is a function for playing Videos
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = ImageVideoCell()
if Image {
cell = tableView.dequeueReusableCell(withIdentifier: "ImageCell", for: indexPath) as! ImageVideoCell
// Display Img
}else {
if video?.isSelected ?? false {
cell = tableView.dequeueReusableCell(withIdentifier: "VideoCell1", for: indexPath) as! ImageVideoCell
}else {
cell = tableView.dequeueReusableCell(withIdentifier: "VideoCell2", for: indexPath) as! ImageVideoCell
}
}
cell.play_pauseButton.tag = indexPath.row
cell.play_pauseButton.setImage(audio?.isSelected ?? false ? #imageLiteral(resourceName: "media-pause") : #imageLiteral(resourceName: "play-button"), for: .normal)
return cell
}
}
// MARK: - AVPlayer
extension AVPlayer {
var isPlaying: Bool {
return ((rate != 0) && (error == nil))
}
}

Swift 2.3 Button to open URL failing with error unrecognised selector

I have created a button to open url links and am failing with an unrecognised selector error. I would normally set the add target to be self just through how i have read online, but for this particular instance i get the error:
cannot convert value of type NSOBJECT ->() -> infoViewcontroller.infoview to expected argument type AnyObject.
So to get around this and what Xcode recommended was to set the target as NSOBJECT.self. However this no longer got an error but crashes upon the click of the button and returns the reason of: [NSObject displayWebLink]: unrecognized selector sent to class 0x106011e58. So i'm just wondering what the correct way of doing this would be and why? Below is my code.
class ActivityInfoView: UICollectionViewCell {
var activity: ActivitysEvents? {
didSet {
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var textView: UITextView = {
let tv = UITextView()
tv.userInteractionEnabled = false
return tv
}()
let dividerLineView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.lightGrayColor()
return view
}()
let urlLinkButton: UIButton = {
let button = UIButton()
button.backgroundColor = UIColor.redColor()
button.titleLabel?.font = UIFont.systemFontOfSize(14)
button.setTitleColor(UIColor.blueColor(), forState: .Normal)
// button.addTarget(self, action: #selector(displayWebLink), forControlEvents: .TouchUpInside)
button.addTarget(NSObject.self, action: #selector(displayWebLink), forControlEvents: .TouchUpInside)
return button
}()
func displayWebLink() {
print("abcdefghijklmnop")
if let urlLink = activity?.url {
// UIApplication.sharedApplication().openURL(NSURL(string: urlLink)!)
UIApplication.sharedApplication().openURL(NSURL(string: urlLink)!, options: [:], completionHandler: nil)
print("dhudududuhdu")
}
}
`
That's not a very helpful error message. The compiler is trying to verify that the correct object defines a method with the name displayWebLink and it seems to be using the closure type as the context where it's searching.
Try telling it where to find the method:
button.addTarget(self, action: #selector(ActivityInfoView.displayWebLink), forControlEvents: .TouchUpInside)
I fixed this issue by changing the button from 'let' to 'lazy var' as below:
lazy var urlLinkButton: UIButton = {
let button = UIButton()
button.backgroundColor = UIColor.redColor()
button.titleLabel?.font = UIFont.systemFontOfSize(14)
button.setTitleColor(UIColor.blueColor(), forState: .Normal)
button.addTarget(self, action: #selector(displayWebLink), forControlEvents: .TouchUpInside)
//button.addTarget(self(), action: #selector(ActivityInfoView.displayWebLink), forControlEvents: .TouchUpInside)
return button
}()

Is there any way to add mouseOver events to a tableView in cocoa?

I want to make my tableView act like this:
When the mouse swipe over a certain row, the row will be highlighted, just like the mouseOver event of a button
It took me some time to work on it based on this hint.
It works for me, correct me if I'm wrong.
Tested with Swift 3.0.2 on macOS 10.12.2 and Xcode 8.2.1
//
// Created by longkai on 30/12/2016.
// Copyright (c) 2016 xiaolongtongxue.com. All rights reserved.
//
import Cocoa
class InboxTableCellView: NSTableCellView {
// MARK: - Outlets
#IBOutlet weak var title: NSTextField!
#IBOutlet weak var sender: NSTextField!
#IBOutlet weak var time: NSTextField!
#IBOutlet weak var snippet: NSTextField!
// MARK: - Mouse hover
deinit {
removeTrackingArea(trackingArea)
}
private var trackingArea: NSTrackingArea!
override func awakeFromNib() {
super.awakeFromNib()
self.trackingArea = NSTrackingArea(
rect: bounds,
options: [NSTrackingAreaOptions.activeAlways, NSTrackingAreaOptions.mouseEnteredAndExited,/* NSTrackingAreaOptions.mouseMoved */],
owner: self,
userInfo: nil
)
addTrackingArea(trackingArea)
}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
NSColor(red: 0.96, green: 0.96, blue: 0.96, alpha: 1.00).set()
// mouse hover
if highlight {
let path = NSBezierPath(rect: bounds)
path.fill()
}
// draw divider
let rect = NSRect(x: 0, y: bounds.height - 2, width: bounds.width, height: bounds.height)
let path = NSBezierPath(rect: rect)
path.fill()
}
private var highlight = false {
didSet {
setNeedsDisplay(bounds)
}
}
override func mouseEntered(with event: NSEvent) {
super.mouseEntered(with: event)
if !highlight {
highlight = true
}
}
override func mouseExited(with event: NSEvent) {
super.mouseExited(with: event)
if highlight {
highlight = false
}
}
}
You need to create a subclass and use tracking areas. That's what buttons do to track mouse hovering.
There's an Apple Sample Code that does exactly what you need - highlighting rows on hover:
HoverTableDemo
It's been thoroughly discussed in WWDC 2011 Session 120
(Ignoring the "Mouse Over is bad GUI" sermon (which you'll ignore anyway… ;-))
#import "MoTableView.h"
#implementation MoTableView
{
NSUInteger mouseRow;
NSRect mouseRowFrame;
}
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
mouseRow = -1;
}
return self;
}
- (void)awakeFromNib
{
[self.window setAcceptsMouseMovedEvents:YES];
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
// Drawing code here.
[[NSColor redColor] set];
NSLogDebug(#"mouseRowFrame: %#", NSStringFromRect(mouseRowFrame));
NSFrameRectWithWidth(mouseRowFrame, 2.);
}
- (void)mouseMoved:(NSEvent *)theEvent
{
NSPoint mouseLocation = [theEvent locationInWindow];
NSPoint viewLocation = [self convertPoint:mouseLocation fromView:nil] ;
NSInteger row = [self rowAtPoint:viewLocation];
if (row != mouseRow) {
mouseRowFrame = [self rectOfRow:row];
[self setNeedsDisplay];
mouseRow = row;
}
}
#end

Hide buttons from titlebar in Cocoa

The Apples Human Interface Guidelines say:
macOS Human Interface Guidelines: Panels
How do I make the very first titlebar in that image (with only a close button). Disabling both Resize and Minimize in IB only make the resize/minimize buttons get disabled. But I want them to disappear. How can I do that?
I believe this should work:
[[window standardWindowButton:NSWindowCloseButton] setHidden:YES];
[[window standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
[[window standardWindowButton:NSWindowZoomButton] setHidden:YES];
Swift code for accepted answer
window!.standardWindowButton(.miniaturizeButton)!.isHidden = true
window!.standardWindowButton(.zoomButton)!.isHidden = true
window!.standardWindowButton(.closeButton)!.isHidden = true
I also needed this but visible for mouse overs - Swift:
var trackingTag: NSTrackingRectTag?
override func mouseEntered(with theEvent: NSEvent) {
if trackingTag == theEvent.trackingNumber {
window!.standardWindowButton(.closeButton)!.alphaValue = 1.00
}
}
override func mouseExited(with theEvent: NSEvent) {
if trackingTag == theEvent.trackingNumber {
window!.standardWindowButton(.closeButton)!.alphaValue = 0.01
}
}
func updateTrackingAreas(_ establish : Bool) {
if let tag = trackingTag {
window!.standardWindowButton(.closeButton)!.removeTrackingRect(tag)
}
if establish, let closeButton = window!.standardWindowButton(.closeButton) {
trackingTag = closeButton.addTrackingRect(closeButton.bounds, owner: self, userData: nil, assumeInside: false)
}
}
override func windowDidLoad() {
window!.ignoresMouseEvents = false
updateTrackingAreas(true)
window!.standardWindowButton(.closeButton)!.alphaValue = 0.01
}
func windowShouldClose(_ sender: Any) -> Bool {
window!.ignoresMouseEvents = true
updateTrackingAreas(false)
return true
}
Visibility is needed but just slightly - 0.01 opacity, to have the tracking area effective.
another way is...
for (id subview in [self window].contentView.superview.subviews) {
if ([subview isKindOfClass:NSClassFromString(#"NSTitlebarContainerView")]) {
NSView *titlebarView = [subview subviews][0];
for (id button in titlebarView.subviews) {
if ([button isKindOfClass:[NSButton class]]) {
[button setHidden:YES];
}
}
}
}

Hide NSWindow title bar

Is there a way to hide the titlebar in an NSWindow? I don't want to have to completely write a new custom window. I can't use NSBorderlessWindowMask because I have a bottom bar on my window, and using NSBorderlessWindowMask makes that disappear. I also tried using setContentBorderThickness:forEdge: with NSMaxYEdge and setting it to 0, that didn't work either.
Any help is appreciated
[yourWindow setStyleMask:NSBorderlessWindowMask];
Starting from OS X 10.10, you can hide title bar.
window1.titlebarAppearsTransparent = true
window1.titleVisibility = .Hidden
Maybe you want to override window style.
window1.styleMask = NSResizableWindowMask
| NSTitledWindowMask
| NSFullSizeContentViewWindowMask
Kind of Welcome screen NSWindow / NSViewController setup (Swift 4.1)
extension NSWindow {
enum Style {
case welcome
}
convenience init(contentRect: CGRect, style: Style) {
switch style {
case .welcome:
let styleMask: NSWindow.StyleMask = [.closable, .titled, .fullSizeContentView]
self.init(contentRect: contentRect, styleMask: styleMask, backing: .buffered, defer: true)
titlebarAppearsTransparent = true
titleVisibility = .hidden
standardWindowButton(.zoomButton)?.isHidden = true
standardWindowButton(.miniaturizeButton)?.isHidden = true
}
}
}
class WelcomeWindowController: NSWindowController {
private (set) lazy var viewController = WelcomeViewController()
private let contentWindow: NSWindow
init() {
contentWindow = NSWindow(contentRect: CGRect(x: 400, y: 200, width: 800, height: 472), style: .welcome)
super.init(window: contentWindow)
let frameSize = contentWindow.contentRect(forFrameRect: contentWindow.frame).size
viewController.view.setFrameSize(frameSize)
contentWindow.contentViewController = viewController
}
}
class WelcomeViewController: NSViewController {
private lazy var contentView = View()
override func loadView() {
view = contentView
}
init() {
super.init(nibName: nil, bundle: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
contentView.backgroundColor = .white
}
}
class View: NSView {
var backgroundColor: NSColor?
convenience init() {
self.init(frame: NSRect())
}
override func draw(_ dirtyRect: NSRect) {
if let backgroundColor = backgroundColor {
backgroundColor.setFill()
dirtyRect.fill()
} else {
super.draw(dirtyRect)
}
}
}
Result
What happens if you get the superview of the close button? Can you hide that?
// Imagine that 'self' is the NSWindow derived class
NSButton *miniaturizeButton = [self standardWindowButton:NSWindowMiniaturizeButton];
NSView* titleBarView = [miniaturizeButton superview];
[titleBarView setHidden:YES];
The only way I know would be to create a window without a titlebar (see
NSBorderlessWindowMask). Note that you can't (easily) create a window without a
titlebar in IB, so you will have to do a bit of work in code (there are a
couple of different approaches, you can probably figure it out).
A big drawback with using a window without a titlebar is that you're now on the
hook for much more of the standard appearance and behaviour - rounded corners
and such.
I had an experience that when I first set content view of my window and then set the window borderless:
[yourWindow setStyleMask:NSBorderlessWindowMask];
Nothing would appear in my window. So i first set the style mask and after that i've set the content view:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// 1. borderless window
[[self window] setStyleMask: NSBorderlessWindowMask];
// 2. create the master View Controller
self.masterViewController = [[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil];
// 3. Add the view controller to the Window's content view
[self.window.contentView addSubview:self.masterViewController.view];
self.masterViewController.view.frame = ((NSView*)self.window.contentView).bounds;
}
And voila, the content of my window has appeared.
Select Window in storyboard or XIB and tick the red circled option.
You can use WAYInAppStoreWindow available on GitHub which works on Yosemite and Mavericks.
Swift
NSApp.mainWindow?.styleMask = .borderless