I'm trying to make RTCMTLNSVideoView available in webrtc for mac to fill the entire container view (videoContainerView is the container NSView, rtcTrack is RTCVideoTrack)
let videoView = RTCMTLNSVideoView(frame: .zero)
videoView.frame = videoContainerView.bounds
videoView.makeBackingLayer()
videoView.layer = CAMetalLayer()
videoView.wantsLayer = true
videoView.layer?.backgroundColor = NSColor.red.cgColor
videoView.layer?.contentsGravity = .resizeAspectFill
rtcTrack?.add(videoView)
videoContainerView.addSubview(videoView)
It results with video being fit only using one size (aspectFit). I can't seem to make it fill the entire container. iOS webrtc has a property videoContentMode. On mac it's missing. How to control the video content mode in this case on mac webrtc? Any ideas appreciated.
Thanks
Easy fix:
if let metalView = videoView.subviews.first(where: { view in view is MTKView }) {
metalView.layerContentsPlacement = .scaleProportionallyToFill
}
Old answer:
As I said in the comments, you have to access private property metalView.
To do this, create file named RTCMTLNSVideoView+Private.h in your project with the following code
#import <MetalKit/MetalKit.h>
#import "WebRTC/RTCMTLNSVideoView.h"
#interface RTCMTLNSVideoView ()
#property(nonatomic, strong) MTKView *metalView;
#end
And then you can reassign content mode:
videoView.metalView.layerContentsPlacement = .scaleProportionallyToFill
Related
I've been working on this Xamarin Forms mobile application and I've been loving it but it's a media player application and the native embedding for the platform specific video player doesn't work. After much debugging I was able to get the audio playing but no video would show up. I think this has to do with the views just not being swapped out appropriately. Unfortunately there isn't much material on how to effectively switch from a Xamarin Forms view to a native view (to see the video) through Xamarin Forms. Any help is appreciated thank you !
I was able to get iOS videos working by using the Xamarin Forms messaging service to Appdelegate class and built the AVPlayer class there. Works great.
playVideo.Clicked += (sender, e) =>
MessagingCenter.Send(this, "ShowVideoPlayer", new
ShowVideoPlayerArguments(videoUrl));
Appdelegate.cs
MessagingCenter.Subscribe<VideoDetailPage,
ShowVideoPlayerArguments>(this, "ShowVideoPlayer",
HandleShowVideoPlayerMessage);
//messaging center class
private void HandleShowVideoPlayerMessage(Page page,
ShowVideoPlayerArguments arguments)
{
var presentingViewController = GetMostPresentedViewController();
var url = NSUrl.FromString(arguments.Url);
var avp = new AVPlayer(url);
var avpvc = new AVPlayerViewController();
avpvc.Player = avp;
avp.Play();
presentingViewController.PresentViewController(avpvc, animated: true,
completionHandler: null);
}
private UIViewController GetMostPresentedViewController()
{
var viewController =
UIApplication.SharedApplication.KeyWindow.RootViewController;
while (viewController.PresentedViewController != null){
viewController = viewController.PresentedViewController;
}
return viewController;
}
However.. Getting this to work with Android is a whole different animal since I have to have deal with .axml layouts I believe.. Any help with this would be greatly appreciate.. Thanks so much guys.
So I figured out an implementation using Native Views, an alternative to Custom Renderers. Such a more stream lined process.
I am creating a tableView in my ViewDidLoad and setting up a custom Source and Cell. That all works great. However the UITableView is displaying separator lines behind my custom view. I can comment out my code for the custom appearance so that the all that loads on screen is an empty UITableView and it still displays the separator lines even though I have set the separatorStyle = UITableViewCellSeparatorStyle.None
var table = new UITableView(View.Bounds);
table.SeparatorStyle = UITableViewCellSeparatorStyle.None;
table.SeparatorColor = UIColor.Clear;
table.TableFooterView = new UIView(CGRect.Empty);
Add(table);
I have also tried setting there color to clear and a blank footer to no avail.
Any help is greatly appreciated.
I know time to time Xamarin ios could be strange, but finally I was able to make it work.
You have to run this code in the ViewDidLayoutSubviews and it works
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
table.SeparatorStyle = UITableViewCellSeparatorStyle.None;
}
You need the following within your override the UITableViewController's ViewDidLoad method (I take it you have subclassed a ViewController for this purpose):
table.SeparatorStyle = UITableViewCellSeparatorStyle.None;
That should do the trick.
Regards,
John
i tried to set a Custom UserAgent for the WKWebView in my Mac App. Unfortunately the specified Custom String never gets set. With the iOS SDK it's not a big deal
NSUserDefaults.standardUserDefaults().registerDefaults(["UserAgent" : "Custom Agent"])
But with the Mac SDK it does not work. I also tried
let url = NSURL(string: startURL)
let req = NSMutableURLRequest(URL: url!)
req.setValue("Custom Agent/1.0", forHTTPHeaderField: "User-Agent")
webView!.loadRequest(req)
Thanky you for every help.
You have to expose some private methods of WKWebView in your ObjC bridging header and call them to change the UA.
Adapted snippets from my mini-browser app:
bridging-header.h
// https://github.com/WebKit/webkit/blob/master/Source/WebKit2/UIProcess/API/Cocoa/WKWebViewPrivate.h
#import WebKit;
#interface WKWebView (Privates)
#property (copy, setter=_setCustomUserAgent:) NSString *_customUserAgent;
#property (copy, setter=_setApplicationNameForUserAgent:) NSString *_applicationNameForUserAgent;
#property (nonatomic, readonly) NSString *_userAgent;
#end
macpin.swift
if let agent = withAgent? {
webview._customUserAgent = agent // specify full UA
} else {
webview._applicationNameForUserAgent = "Version/8.0.2 Safari/600.2.5"
// appended to UA, mimicing Safari
}
webview.loadRequest(NSURLRequest(URL: url))
Now, in Swift 2, you can do it without Obj-C with help of new selector API.
Like this:
let webView = WKWebView()
webView.performSelector("_setApplicationNameForUserAgent:", withObject: "My App User Agent addition")
But avoid to use it in production code in this form. Try to hide it somehow :)
I am trying to add an outlet into my viewcontroller for a toolbar item in my window controller. I have tried playing around with first responder and bindings but have not been able to find any solutions.
A similar question that was answered provided some insight but no one has mentioned anything about IBOutlets other than still asking how to add them in the comments. The answer has been accepted so i am assuming no one will add to it.
How to use NSToolBar in Xcode 6 and Storyboard?
Incase my question is unclear at all, i would like to be able to add this to my storyboard program
#IBOutlet weak var Mytoolbar: NSToolbarItem!
func enabletoolbar()
{
Mytoolbar.action = "FunctionIn.ViewController.swift"
Mytoolbar.enabled = true
}
I found a decent workaround by adding IBOutlets to my custom NSWindow class and using the storyboard to connect my views to the IBOutlets. Then, I accessed these views from my NSViewController class by getting them from the custom NSWindow.
Basically you need to set the action and other properties to the toolbaritem but not in the toolbar. So try the same.
i ended up doing this in my view controller which seems to work
override func viewDidLayout() {
var x = self.view.window?.toolbar?.items[1].label
println(x)
if(self.view.window?.toolbar?.items[0].label! != "Check")
{
toobarediting()
}
println("didlay")
}
func toobarediting() {
self.view.window?.toolbar?.insertItemWithItemIdentifier("Check", atIndex: 0)
}
func toolbarcheck(functiontoset: Selector) {
var y = self.view.window?.toolbar?.items[0] as NSToolbarItem
y.action = functiontoset
if(functiontoset != nil)
{
y.enabled = true
}
}
It seems to allow me to make the tool bar button clickable/unclickable when ever i require it to change it just seems so much more bulky and error prone than
myitem.enable = fale
myitem.action = nil
is this really the best way for a storyboard based application in osx?
While connectiong IBActions works by using either the First Responder or by adding an "Object" to the scene, then changing its class to the window's view controller class, this doesn't help with IBOutlets and delegates that you'd like to point to the view controller.
Here's a work-around for that:
Add the Toolbar to the View Controller, not to its Window. That way, you can make all the IBOutlet connections in the View Controller Scene easily. I've done that for years and found no issues with it, even when using Tabs.
You'll have to assign the window's toolbar in code, then. E.g. like this:
#interface ViewController ()
#property (weak) IBOutlet NSToolbar *toolbar; // connect this in your storyboard to the Toolbar that you moved to the View Controller Scene
#end
- (void)viewWillAppear {
[super viewWillAppear];
self.view.window.toolbar = self.toolbar;
}
I am building a Mac application using Swift. Therefor, I want to make a WKWebView transparent, so it shows the text of the loaded HTML, but the background of my underlaying NSWindow is visible.
I tried
webView.layer?.backgroundColor = NSColor.clearColor().CGColor;
which hadn't any effect. WKWebView inherits from NSView, but I don't know if this helps.
Another solution would be to insert a NSVisualEffectView as the background of the WebView, but I don't know how to accomplish that, either!
Use this in macOS 10.12 and higher:
webView.setValue(false, forKey: "drawsBackground")
It was not supported, then they fixed it:
https://bugs.webkit.org/show_bug.cgi?id=134779
The way to make it transparent is to:
myWebView.opaque = false
Code below works for me perfectly, also color is set to clearColor by default.
[wkWebView setValue:YES forKey:#"drawsTransparentBackground"];
I used this for macOS 10.12. without problems in OjbC:
[self.webView setValue:#YES forKey:#"drawsTransparentBackground"];
Under macOS 10.13.+ I got the following console warning message:
-[WKWebView _setDrawsTransparentBackground:] is deprecated and should not be used
The ONLY working solution was:
[self.webView setValue:#(NO) forKey:#"drawsBackground"];
I tried the below in many scenarios and it didn't work:
give the webView and the enclosingScrollView a layer and edit it's properties (backgroundColor, isOpaque)
give the webView and the enclosingScrollView a clear background color
inject javascript without the setValue forKey: in the webview.
Additionally I did use:
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
{
if (self.isWebviewsBackgroundTransparent) {
[self insertTransparentBackgroundTo:webView];
}
}
- (void)insertTransparentBackgroundTo:(WKWebView *)webView
{
NSString *transparentBackgroundJSSString = #"document.body.style = document.body.style.cssText + \";background: transparent !important;\";";
[webView evaluateJavaScript:transparentBackgroundJSSString completionHandler:nil];
}
Updated, slightly better solution (2022). There is a private property drawsBackground on WKWebViewConfiguration. This property has been introduced in macOS 10.14 so it won't go away.
//https://opensource.apple.com/source/WebKit2/WebKit2-7610.2.11.51.8/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h.auto.html
//One can verify that the property still exists:
//https://github.com/WebKit/WebKit/blob/main/Source/WebKit/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h
#property (nonatomic, setter=_setDrawsBackground:) BOOL _drawsBackground WK_API_AVAILABLE(macos(10.14), ios(12.0));
Example:
let configuration = WKWebViewConfiguration()
var requiresDrawBackgroundFallback = false
if #available(OSX 10.14, *) {
configuration.setValue(false, forKey: "sward".reversed() + "background".capitalized) //drawsBackground KVC hack; works but private
} else {
requiresDrawBackgroundFallback = true
}
let webView = WKWebView(frame: .zero, configuration: configuration)
if requiresDrawBackgroundFallback {
webView.setValue(false, forKey: "sward".reversed() + "background".capitalized) //drawsBackground KVC hack; works but private
}