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))
}
}
I need set backgroud color in title to transparent, but it is not set to transparent, i am using custom dialog pin in MAPKit. whats is wrong ?
Backgroud View color is set to CLear Color..
And programatically is set color to Clear Color:
customMarkerXIB.backgroundColor = UIColor.clearColor()
import UIKit
#IBDesignable class Widget: UIView {
var view: UIView!
var nibName: String = "Widget"
#IBOutlet weak var titleLabel: UILabel!
/* #IBInspectable var image: UIImage? {
get {
return imageView.image
}
set(image) {
imageView.image = image
}
}
*/
#IBInspectable var title: String? {
get {
return titleLabel.text
}
set(title) {
titleLabel.text = title
}
}
func setSelectedState(){
println("hola")
}
// init
override init(frame: CGRect) {
// properties
super.init(frame: frame)
// Set anything that uses the view or visible bounds
setup()
}
required init(coder aDecoder: NSCoder) {
// properties
super.init(coder: aDecoder)
// Setup
setup()
}
func setup() {
view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
addSubview(view)
}
func loadViewFromNib() -> UIView {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: nibName, bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as UIView
return view
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
}
*/
}
Loading custom annotation
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
var identifier = "CustomAnnotation"
var position = 0;
if let mapPin = annotation as? MyAnnotation {
position = mapPin.position; // assosiate annotation with a position
}
if annotation.isKindOfClass(MyAnnotation) {
var marker = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)
if marker == nil {
marker = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier)
marker.tag = position;
marker.image = UIImage(named: "mapa_pin")
marker.centerOffset = CGPointMake(0, -10)
marker.canShowCallout = true
marker.backgroundColor = UIColor.clearColor()
//var pointTitle = marker!.annotation.title! as String
/* var label:UILabel = UILabel(frame: CGRectMake(0, CGFloat(floorf((56.0-20)/2)), 26.0, 20))
label.backgroundColor = UIColor.clearColor()
label.text = "asdfasdfasdfasd"
label.textAlignment = NSTextAlignment.Center
label.font = UIFont.systemFontOfSize(11.0)
marker.addSubview(label) */
var customMarkerXIB : Widget = Widget(frame: CGRect(x: 0, y: 250, width: 300, height: 150))
customMarkerXIB.backgroundColor = UIColor.clearColor()
customMarkerXIB.title = "olakease";
customMarkerXIB.setSelectedState()
marker.rightCalloutAccessoryView = customMarkerXIB
// Callout
/* var button = UIButton.buttonWithType(.DetailDisclosure) as UIButton
marker!.leftCalloutAccessoryView = button
var image = UIImageView(image: UIImage(named: "mapa_pin"))
marker!.rightCalloutAccessoryView = image*/
} else {
marker!.annotation = annotation
}
return marker
}
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
I'm looking for the best way to change the backgroundColor of an NSView. I'd also like to be able to set the appropriate alpha mask for the NSView. Something like:
myView.backgroundColor = [NSColor colorWithCalibratedRed:0.227f
green:0.251f
blue:0.337
alpha:0.8];
I notice that NSWindow has this method, and I'm not a big fan of the NSColorWheel, or NSImage background options, but if they are the best, willing to use.
Yeah, your own answer was right. You could also use Cocoa methods:
- (void)drawRect:(NSRect)dirtyRect {
// set any NSColor for filling, say white:
[[NSColor whiteColor] setFill];
NSRectFill(dirtyRect);
[super drawRect:dirtyRect];
}
In Swift:
class MyView: NSView {
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
// #1d161d
NSColor(red: 0x1d/255, green: 0x16/255, blue: 0x1d/255, alpha: 1).setFill()
dirtyRect.fill()
}
}
An easy, efficient solution is to configure the view to use a Core Animation layer as its backing store. Then you can use -[CALayer setBackgroundColor:] to set the background color of the layer.
- (void)awakeFromNib {
self.wantsLayer = YES; // NSView will create a CALayer automatically
}
- (BOOL)wantsUpdateLayer {
return YES; // Tells NSView to call `updateLayer` instead of `drawRect:`
}
- (void)updateLayer {
self.layer.backgroundColor = [NSColor colorWithCalibratedRed:0.227f
green:0.251f
blue:0.337
alpha:0.8].CGColor;
}
That’s it!
If you are a storyboard lover, here is a way that you don't need any line of code.
Add NSBox as a subview to NSView and adjust NSBox's frame as the same with NSView.
In Storyboard or XIB change Title position to None, Box type to Custom, Border Type to "None", and Border color to whatever you like.
Here is a screenshot:
This is the result:
If you setWantsLayer to YES first, you can directly manipulate the layer background.
[self.view setWantsLayer:YES];
[self.view.layer setBackgroundColor:[[NSColor whiteColor] CGColor]];
Think I figured out how to do it:
- (void)drawRect:(NSRect)dirtyRect {
// Fill in background Color
CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
CGContextSetRGBFillColor(context, 0.227,0.251,0.337,0.8);
CGContextFillRect(context, NSRectToCGRect(dirtyRect));
}
edit/update: Xcode 8.3.1 • Swift 3.1
extension NSView {
var backgroundColor: NSColor? {
get {
guard let color = layer?.backgroundColor else { return nil }
return NSColor(cgColor: color)
}
set {
wantsLayer = true
layer?.backgroundColor = newValue?.cgColor
}
}
}
usage:
let myView = NSView(frame: NSRect(x: 0, y: 0, width: 100, height: 100))
print(myView.backgroundColor ?? "none") // NSView's background hasn't been set yet = nil
myView.backgroundColor = .red // set NSView's background color to red color
print(myView.backgroundColor ?? "none")
view.addSubview(myView)
I went through all of these answers and none of them worked for me unfortunately. However, I found this extremely simple way, after about an hour of searching : )
myView.layer.backgroundColor = CGColorCreateGenericRGB(0, 0, 0, 0.9);
Best Solution :
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.wantsLayer = YES;
}
return self;
}
- (void)awakeFromNib
{
float r = (rand() % 255) / 255.0f;
float g = (rand() % 255) / 255.0f;
float b = (rand() % 255) / 255.0f;
if(self.layer)
{
CGColorRef color = CGColorCreateGenericRGB(r, g, b, 1.0f);
self.layer.backgroundColor = color;
CGColorRelease(color);
}
}
In Swift:
override func drawRect(dirtyRect: NSRect) {
NSColor.greenColor().setFill()
NSRectFill(dirtyRect)
super.drawRect(dirtyRect)
}
Use NSBox, which is a subclass of NSView, allowing us to easily style
Swift 3
let box = NSBox()
box.boxType = .custom
box.fillColor = NSColor.red
box.cornerRadius = 5
Without doubt the easiest way, also compatible with Color Set Assets:
Swift:
view.setValue(NSColor.white, forKey: "backgroundColor")
Objective-C:
[view setValue: NSColor.whiteColor forKey: "backgroundColor"];
Interface Builder:
Add a user defined attribute backgroundColor in the interface builder, of type NSColor.
Just set backgroundColor on the layer (after making the view layer backed).
view.wantsLayer = true
view.layer?.backgroundColor = CGColor.white
I tested the following and it worked for me (in Swift):
view.wantsLayer = true
view.layer?.backgroundColor = NSColor.blackColor().colorWithAlphaComponent(0.5).CGColor
In Swift 3, you can create an extension to do it:
extension NSView {
func setBackgroundColor(_ color: NSColor) {
wantsLayer = true
layer?.backgroundColor = color.cgColor
}
}
// how to use
btn.setBackgroundColor(NSColor.gray)
In swift you can subclass NSView and do this
class MyView:NSView {
required init?(coder: NSCoder) {
super.init(coder: coder);
self.wantsLayer = true;
self.layer?.backgroundColor = NSColor.redColor().CGColor;
}
}
This supports changing systemwide appearance (turning dark mode on or off) while the application is running. You can also set the background colour in Interface Builder, if you set the class of the view to BackgroundColorView first.
class BackgroundColorView: NSView {
#IBInspectable var backgroundColor: NSColor? {
didSet { needsDisplay = true }
}
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
wantsLayer = true
}
required init?(coder decoder: NSCoder) {
super.init(coder: decoder)
wantsLayer = true
}
override var wantsUpdateLayer: Bool { return true }
override func updateLayer() {
layer?.backgroundColor = backgroundColor?.cgColor
}
}
Have a look at RMSkinnedView. You can set the NSView's background color from within Interface Builder.
Just small reusable class (Swift 4.1)
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)
}
}
}
// Usage
let view = View()
view.backgroundColor = .white
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];
}
}
}
}