Safari view in swiftui displaying empty view - swiftui

Hi everyone I am trying to display safari view as full screen modal using ZStack
ZStack
{
HStack
{
VStack
{
Safari(url: url)
}
}
}
.edgesIgnoringSafeArea(.all)
.offset(x: 0, y: self.modalPresented ? 0 : 5000)
But the output I get is a white empty view. And also the navigation bar is still visible.
Can someone please help me explain what is going on?
https://i.stack.imgur.com/Qqd64.jpg

This is how we call a url :
url = URL(string: "https://www.hackingwithswift.com")
UIApplication.shared.open(url)
If you are using Scene delegate, then you should handle url first, so go to Scene delegate and add this fuction, if it does not exists already:
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let url = URLContexts.first?.url else {
return
}
//Handle URL here
}
Then you url call should be like this:
UIApplication.shared.open(url, options: [:], completionHandler: nil)

Related

Using .redacted & AsyncImage together

I would like to use .redacted on the entire view until the image is successfully loaded into AsyncImage.. Currently I cannot find a way to complete this.. My last attempt was this..
struct MyView: View {
var body: some View {
VStack {
//Other Views
AsyncImage(url: URL(string: "https://cdn2.thecatapi.com/images/7CGV6WVXq.jpg")!) { phase in
if let image = phase.image {
image
//Some image modifiers
self.imageLoaded = true // Of course this won't work in this closure but I cannot think of where else to put it.
}
}
}.redacted(reason: imageLoaded ? .placeholder : []) // <-- How to redact programmatically?
}
}
The closest solution is to use onDisappear modifier which is triggered when the view disappears (which mean the image had loaded
VStack {
//Other Views
AsyncImage(url: URL(string: "https://cdn2.thecatapi.com/images/7CGV6WVXq.jpg")!) { phase in
if let image = phase.image {
image
} else {
// When the image is loading, or has failed to load
// You can use any view (example: a loading view or placeholder)
RoundedRectangle(cornerRadius: 10)
.onDisappear {
imageLoaded = true
}
}
}
.frame(width: 300, height: 300)
}
.redacted(reason: imageLoaded ? [] : .placeholder)

Showing Interstitial Ad from button that also toggles another view from sheet

so i have this test app that consists of 2 views. The parent view has a button that toggles the second view (Bottom Modal Sheet). My goal is to show an AdMob interstitial ad when the button is clicked. But still have the second view when the ad is dismissed. Currently, the ad appears but when dismissing the ad, it goes back to the parent view without the second view toggled. Is it possible to perhaps stack the Ad view on top of the second view so when dismissing the ad, the user is already in the second view?
import GoogleMobileAds
import SwiftUI
import UIKit
struct ContentView: View {
#State var showingTest = false
#State var showingDisclaimer = false
//Ad
var interstitial: Interstitial
init() {
self.interstitial = Interstitial()
}
var body: some View {
// QuestionsView()
// NavigationView {
VStack {
Button(action: {
self.showingTest.toggle()
self.interstitial.showAd()
}) {
Text("take the test!")
.fontWeight(.bold)
.foregroundColor(Color.white)
}
.frame(minWidth: 0, maxWidth: .infinity)
.padding()
.foregroundColor(.gray)
.background(Color("raisinblack"))
.cornerRadius(10)
.font(.title)
.sheet(isPresented: $showingTest) {
QuestionsView()
}.padding()
.shadow(radius: 5)
}
.padding()
.frame(minWidth: 0, maxWidth: .infinity)
.navigationBarTitle("rice purity test.")
}
}
I'm new to swiftUI so I'm not sure how to go about making this work. I understand that the problem arises because I'm trying to present two views at the same time.
The Error:
Warning: Attempt to present <_TtGC7SwiftUIP10$1c95b7a6c22SheetHostingControllerVS_7AnyView_: 0x1056344f0> on <_TtGC7SwiftUI19UIHostingControllerV14RicePurityTest11ContentView_: 0x10560f280> whose view is not in the window hierarchy!
The Interstitial Class
final class Interstitial: NSObject, GADInterstitialDelegate {
var interstitial: GADInterstitial = GADInterstitial(adUnitID: "ca-app-pub-3940256099942544/4411468910")
override init() {
super.init()
self.LoadInterstitial()
}
func LoadInterstitial() {
let req = GADRequest()
self.interstitial.load(req)
self.interstitial.delegate = self
}
func showAd() {
if self.interstitial.isReady {
let root = UIApplication.shared.windows.first?.rootViewController
self.interstitial.present(fromRootViewController: root!)
} else {
print("Not Ready")
}
}
func interstitialDidDismissScreen(_ ad: GADInterstitial) {
self.interstitial = GADInterstitial(adUnitID: "ca-app-pub-3940256099942544/4411468910")
self.LoadInterstitial()
}
/// Tells the delegate an ad request succeeded.
func interstitialDidReceiveAd(_ ad: GADInterstitial) {
print("interstitialDidReceiveAd")
}
/// Tells the delegate an ad request failed.
func interstitial(_ ad: GADInterstitial, didFailToReceiveAdWithError error: GADRequestError) {
print("interstitial:didFailToReceiveAdWithError: \(error.localizedDescription)")
}
/// Tells the delegate that an interstitial will be presented.
func interstitialWillPresentScreen(_ ad: GADInterstitial) {
print("interstitialWillPresentScreen")
}
/// Tells the delegate the interstitial is to be animated off the screen.
func interstitialWillDismissScreen(_ ad: GADInterstitial) {
print("interstitialWillDismissScreen")
//showingTest.toggle()
}
/// Tells the delegate that a user click will open another app
/// (such as the App Store), backgrounding the current app.
func interstitialWillLeaveApplication(_ ad: GADInterstitial) {
print("interstitialWillLeaveApplication")
}
}
func showAd() {
if self.interstitial.isReady {
let root = UIApplication.shared.windows.last?.rootViewController
// you can also use: UIApplication.shared.keyWindow.rootViewController
self.interstitial.present(fromRootViewController: root!)
} else {
print("Not Ready")
}
}

WkWebView has spacing appear after it in SwiftUI

I am having a problem where a spacing appears after the content of my WKWebView (picture included at the very bottom). I am displaying a grouping of several live streams from Facebook, but this issue keeps showing up. I have not found any solutions on Stackoverflow or other websites. My webviews are being scaled to fit in the main view as well. This is all being done in SwiftUI also and I tried adding an offset but then this added a long empty space at the bottom of the view, as expected. I appreciate any possible help because I am not exactly sure the cause of this, and I am not sure if this is a Facebook issue or something I am doing. Thank you.
Here is the code in my main body view that displays the web views:
ScrollView {
HStack {
Text("Most Recent Livestream")
.font(.title)
.padding([.top, .leading])
Spacer()
}
VStack {
if (self.fb.showWebViews != false) {
fb.getwebView(index: 0).scaledToFit()
}
}
VStack {
if (self.fb.showWebViews != false) {
Text("\(fb.getVideoDate(index: 1))")
fb.getwebView(index: 1).scaledToFit()
}
}
VStack {
if (self.fb.showWebViews != false) {
Text("\(fb.getVideoDate(index: 2))")
fb.getwebView(index: 2).scaledToFit()
}
}
VStack {
if (self.fb.showWebViews != false) {
Text("\(fb.getVideoDate(index: 3))")
fb.getwebView(index: 3).scaledToFit()
}
}
VStack {
if (self.fb.showWebViews != false) {
Text("\(fb.getVideoDate(index: 4))")
fb.getwebView(index: 4).scaledToFit()
}
}
Button(action: {
print("LEARN MORE!")
}) {
Image(systemName: "questionmark.circle")
Text("Want to view more livestreams?")
.foregroundColor(Color(.label))
}.padding([.top, .leading])
Spacer()
}
Here is the webview code:
struct WebView2 : UIViewRepresentable {
// Instence Var of request URL
var request: URLRequest
// Creates the UIView of the WebView
func makeUIView(context: Context) -> WKWebView {
return WKWebView()
}
// Updates the Webview
/// With disable scrolling, backround becomes opaue, and reloads page with the quested URL
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.scrollView.isScrollEnabled = false
uiView.isOpaque = false
uiView.load(request)
}
}
Here is a picture of what it looks like with the spacing:
It turned out that in order to fix this problem all I had to do was remove the .scaledToFit() on each WebView in the VStacks. Then after removing those, I then had to put .frame(height: 233) on each WebView in the VStacks in order to make then all display completly, since they always will be 233 in height.

How to present a full screen AVPlayerViewController in SwiftUI

In SwiftUI, it seems like the best way to set up an AVPlayerViewController is to use the UIViewControllerRepresentable in a fashion somewhat like this...
struct PlayerViewController: UIViewControllerRepresentable {
var videoURL: URL?
private var player: AVPlayer {
return AVPlayer(url: videoURL!)
}
func makeUIViewController(context: Context) -> AVPlayerViewController {
let controller = AVPlayerViewController()
controller.modalPresentationStyle = .fullScreen
controller.player = player
controller.player?.play()
return controller
}
func updateUIViewController(_ playerController: AVPlayerViewController, context: Context) {
}
}
However from the documentation that the only way to show this controller in a full-screen way is to present it using a sheet.
.sheet(isPresented: $showingDetail) {
PlayerViewController(videoURL: URL(string: "..."))
.edgesIgnoringSafeArea(.all)
}
This doesn't give you a full-screen video with a dismiss button but a sheet modal which can be swiped away instead.
In standard non-SwiftUI Swift, it would seem like the best way would be to present this controller...
let controller = PlayerViewController(videoURL: URL(string: "..."))
self.present(controller, animated: true)
...but SwiftUI doesn't have a self.present as part of it. What would be the best way to present a full-screen video in SwiftUI?
Instead of sheet I would use the solution with ZStack (probably with custom transition if needed), like below
ZStack {
// ... other your content below
if showingDetail { // covers full screen above all
PlayerViewController(videoURL: URL(string: "..."))
.edgesIgnoringSafeArea(.all)
//.transition(AnyTransition.move(edge: .bottom).animation(.default)) // if needed
}
}

Putting an Image() from url inside an HStack inside of Button inside of List makes it go black

I've been trying to make a List of buttons, and when it gets clicked, it calls some code, I also need some 'thumbnails' to go along with every button, so I made a HStack for each button and put it all on a List, now the thumbnail doesn't render, BTW, it renders system images and local assets just fine, it's just the images grabbed from the network
you can just copy-paste this into ContentView.swift to reproduce it
import SwiftUI
func artwork() -> Image
{
let art = "https://via.placeholder.com/150"
if let url = URL(string: art), let data = try? Data(contentsOf: url), let image = UIImage(data: data)
{
return Image(uiImage: image)
}
else
{
return Image(systemName: "book")
}
}
struct ContentView: View
{
var body: some View
{
List
{
Button(action: {...my code...})
{
HStack
{
artwork()
}
... some other info
}
}
}
}
This issue is similar to Avoid button styling its content in SwiftUI
You just have to add .renderingMode(.original) to your Image like so:
func artwork() -> Image
{
let art = "https://via.placeholder.com/150"
if let url = URL(string: art), let data = try? Data(contentsOf: url), let image = UIImage(data: data)
{
return Image(uiImage: image)
}
else
{
return Image(systemName: "book")
}
}
struct ContentView: View
{
var body: some View
{
List
{
Button(action: {})
{
HStack
{
artwork().renderingMode(.original)
}
}
}
}
}