Unable to display subview added to WKWebView - ios

I am creating an embedded view for an app using Swift and WKWebView. I am stuck in adding and displaying the UIProgressView (my subview).
Whenever I add it on story builder (on top of the view) and then run the app it does not show because of my code (I associate self.view to the instance of WKWebView that I create).
I hence tried an alternative approach and added it programmatically but won't work either.
Here is my code (for the first approach just ignore the programmatic declaration of UIProgressView):
import UIKit
import WebKit
class SupportWebView: UIViewController, WKNavigationDelegate {
#IBOutlet var containerView : UIView? = nil
#IBOutlet var progressView : UIProgressView? = nil
var webView: WKWebView?
dynamic var myProgress: Double = 0
private var myContext = 0
override func loadView() {
super.loadView()
self.webView = WKWebView()
self.view = self.webView
self.webView?.navigationDelegate = self
self.webView?.addObserver(self, forKeyPath: "estimatedProgress", options: .New, context: &myContext)
let progressView = UIProgressView(progressViewStyle: .Bar)
progressView.center = view.center
progressView.progress = 20.0/30.0
progressView.trackTintColor = UIColor.lightGrayColor()
progressView.tintColor = UIColor.blueColor()
self.webView?.addSubview(progressView)
// self.webView.addSubview(progressView)
}
I tried to add the UIProgressView programmatically to the WKWebView view but it won't work.. any suggestion on how to fix this? It seems to display only the main WKWebView and ignore the subviews (they may be rendered before the web view rendering and hence they disappear).

I tested out your code and got it to render the progressView by changing progressView.center = view.center to something like progressView.frame = CGRectMake(100.0, 100.0, 200.0, 5.0). I tested without doing anything on the Storyboard.

Related

IBOutlet of AnimationView in lottie is not showing the animation

I've created an #IBOutlet weak var animationView: AnimationView! Then on ViewController I added a UIView changed its class from UIView to AnimationView. The after connecting the outlet I'm adding this code in viewDidLoad() of my class:
let animation = Animation.named("sticky", subdirectory: "Lottie-files")
animationView.animation = animation
animationView.loopMode = .loop
animationView.contentMode = .scaleAspectFill
Then in viewDidAppear() I've added:
animationView.play()
But when I run it nothing shows up. I also see this in the terminal:
[Storyboard] Unknown class AnimationView in Interface Builder file.
This warning is solved by doing
But still the animation is not appearing. No warning, no error it just not displaying.
You should start animation in viewDidAppear or something called after viewDidLoad, for example: viewWillAppear
public override func viewDidLoad() {
super.viewDidLoad()
addAnimation(to: animationView, name: "sticky")
}
public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
animationView.play()
}
private func addAnimation(to view: AnimationView, name: String) {
let animation = Animation.named(name, subdirectory: "Lottie-files")
view.animation = animation
view.loopMode = .loop
view.contentMode = .scaleAspectFill
}
BONUS
Ekramul Hoque's Article about View Controller's Lifecycle
Make sure these
You should write Lottie to your view's Identity Inspector section in Interface Builder's right bar.
Check for subdirectory path. It can be because Xcode is unable to locate file in Lottie-files subdirectory. Try moving it in the main directory and try.
You can set programmatically
import Lottie
then add animation view in your view controller, set lottie animation in your storyboard -> animationView -> class -> AnimationView and module -> Lottie
#IBOutlet weak var animationView: AnimationView!
//Initialise a Lottie view with frame
let customAnimationView = AnimationView(name: "Your lotti file name")
customAnimationView.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
//Do your configurations
customAnimationView.loopMode = .loop
customAnimationView.backgroundBehavior = .pauseAndRestore
//And play
customAnimationView.play()
animationView.addSubview(customAnimationView)
As per the lottie document you should call
play()
function inside viewDidAppear.
public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
animationView.play()
}
Please check the following link
https://github.com/airbnb/lottie-ios/blob/master/Example/lottie-swift/ViewController.swift
NOTE : In some case you need to check sub directory problem
You need to add Folder References
Not a Groups
for more information on this section please check the following link.
http://www.thomashanning.com/xcode-groups-folder-references/

IOS Swift what am I messing up on in my UIView adding a subview

I have a UIView and set constraints on it as the image below shows . When I open it in the simulator it works correctly . The problem comes when I try and add a WKWEBview to display a video and add the subview . I want the video to take the dimensions of the UIView but the video looks extra small and the UIView looks like it shrinks . How can I fix that so that the video takes the full dimensions of the UIView . As you can see from the constraints it set to trail and leading and the video is not taking up that width even though it is large enough . The only thing I can think of for fixing this is adding a
addChildViewController(ViewController)
however the WKWebview does not have a Controller any suggestions would be great .
class ExampleTable: UIViewController, WKUIDelegate {
#IBOutlet weak var newView: UIView!
var myWKWEBVIEW: WKWebView?
override func viewDidLoad() {
super.viewDidLoad()
myWKWEBVIEW?.uiDelegate = self
guard let movieURL = URL(string: "my video url")
else { return }
let webConfiguration = WKWebViewConfiguration()
webConfiguration.allowsInlineMediaPlayback = true
webConfiguration.mediaTypesRequiringUserActionForPlayback = .audio
myWKWEBVIEW = WKWebView(frame: newView.frame,configuration: webConfiguration)
newView.addSubview(myWKWEBVIEW!)
DispatchQueue.main.async (execute: { () -> Void in
self.myWKWEBVIEW?.loadHTMLString("<video height=\"\(self.newView.frame.height)\" width=\"\(self.newView.frame.width)\" muted=\"muted\" autoplay=\"autoplay\" src=\"\(movieURL)\" playsinline/>", baseURL: nil)
})
}
}
My constraints
How it looks with no addsubview
How it looks when I add subview to display video
Can you please check the below code :
myWKWEBVIEW = WKWebView(frame: CGRect(origin: CGPoint(x:0,y:0), size: newView.frame.size),configuration: webConfiguration)

How do I make my ImageView scrollable without affecting the rest of the view?

How Do I add multipleImages for the top part and have it scrollable without moving the rest of the content? Also, how do I have the little dots at the bottom to indicate which image I'm on? My code for the image is down below.
import SDWebImage
#IBOutlet weak var headerImage: UIImageView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let imageUrl:NSURL? = NSURL(string: headerPhoto!)
if let url = imageUrl {
headerImage.sd_setImage(with: url as URL!)
}
}
You are looking for something called image slide show or image slider.
Instead of creating them by yourself which requires lots of effort, here is a GitHub library that is easy to use.
Basicly the way slider works is that it is a horizontal scroll view and each cell in the scroll view is an image so that you can scroll. Then, put a fixed page index element on the bottom of the scroll view to tell you which image you are currently at.
To use it, create a UIView in your viewcontroller and set both class and module to ImageSlideshow. Then connect it to your ViewController.swift as IBOutLet.
Then create an array of image urls
let alamofireSource = [AlamofireSource(urlString: "imgurl1")!, AlamofireSource(urlString: "imgurl2")!, AlamofireSource(urlString: "imgurl3")!]
And finally in your viewDidLoad() function:
override func viewDidLoad() {
super.viewDidLoad()
slideshow.backgroundColor = UIColor.white
slideshow.slideshowInterval = 5.0
slideshow.pageControlPosition = PageControlPosition.underScrollView
slideshow.pageControl.currentPageIndicatorTintColor = UIColor.lightGray
slideshow.pageControl.pageIndicatorTintColor = UIColor.black
slideshow.contentScaleMode = UIViewContentMode.scaleAspectFill
slideshow.setImageInputs(alamofireSource)
}

Strange Margin in WKWebView

I have a UIViewController with a few UIViews (built using Interface Builder) including one that I want to use as a WKWebView. I have been able to create the WKWebView and load it as a subview to one of these UIViews -- but when I load the URL I get this strange padding on the top and left. I had the same issue when I use the UIWebView but was able to solve it using
self.automaticallyAdjustsScrollViewInsets = false;
However this does not seem to help at all with the WKWebView that has been loaded dynamically.
I also get the same padding when loading a page from the web so I know its not in my local html.
Edit: I am beginning to wonder whether autolayout in the container UIView is causing this...
Here is the relevant code:
var webView:WKWebView!
#IBOutlet var containerView : UIView?
#IBOutlet weak var webContainer: UIView!
override func loadView() {
super.loadView()
self.webView = WKWebView()
if(self.webView != nil){
self.containerView = self.webView!
self.containerView!.frame = self.webContainer.frame
self.webContainer.addSubview(self.containerView!)
}
}
override func viewDidLoad() {
super.viewDidLoad()
let bundle = NSBundle.mainBundle()
let url = bundle.URLForResource("index", withExtension: "html")
let request = NSURLRequest(URL: url!)
webView.loadRequest(request)
}
Here is what it looks like. The BG color of the UIView container is dark grey -- and you'll also note that the html seems to extend beyond the UIView even though I set the frame of the WebView to be the same as the UIView container:
This is because WKWebView preserves space for the navigation bar by using an appropriate contentInset. However, since your WKWebView is a subview, this adjustment is not necessary anymore.
self.webView.scrollView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
It is important to do this after the viewDidLoad method. For example in didFinishedNavigation in the WKNavigationDelegate
self.automaticallyAdjustsScrollViewInsets = NO;
if (#available(iOS 11.0, *)) {
self.webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
Should be used WKNavigationDelegate
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
NSString *cssString = #"body { padding:0; margin:0}";
NSString *jsString = [NSString stringWithFormat:#"var style = document.createElement('style'); style.innerHTML = '%#'; document.head.appendChild(style);", cssString];
[webView evaluateJavaScript:jsString completionHandler:nil];}

Adding View Programmatically from ViewController super class doesn't show in front

I have a BaseViewController that my UIViewControllers extend so i can have explicit functions that i dont need to rewrite. Something i would like would be a functions such as self.showSpinner() and the viewController would show the spinner
My Code looks like this
class BaseViewController: UIViewController {
var actvIndicator : UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
self.actvIndicator = UIActivityIndicatorView(activityIndicatorStyle: .WhiteLarge)
self.actvIndicator.color = UIColor.blackColor()
self.actvIndicator.backgroundColor = UIColor.blackColor()
self.actvIndicator.frame = CGRectMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2, 100, 100);
self.actvIndicator.center = self.view.center
self.actvIndicator .startAnimating()
self.view.addSubview(self.actvIndicator)
self.actvIndicator.bringSubviewToFront(self.view)
self.edgesForExtendedLayout = UIRectEdge.None
self.navigationController?.navigationBar.translucent = false
}
func showSpinner(){
self.actvIndicator.startAnimating()
}
func hideSpinner(){
self.actvIndicator.stopAnimating()
}
}
And my viewcontrollers looks like this
class MyProjectViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.showSpinner()
}
}
MyProjectViewController have UITableView that fills the entire screen. When i set tblProjects.alpha = 0 i can see the spinner. But i want it in the front.
i also tried self.view.bringSubviewToFront(self.actvIndicator)
What am i missing?
A couple quick notes before I get into what I think your problem is:
When you add a subview it is automatically added to the top layer, no need for the bringSubviewToFront: in viewDidLoad: (which is being used wrong anyway).
You should not set view frames in viewDidLoad: (e.g. centering a view). Frames are not setup yet, so you should move that to viewWillAppear: or some other variant.
Now your issue is most likely a view hierarchy problem (further confirmed by your comment) and thus can probably be fixed by pushing the spinner to the front every time you want it to be shown, like:
func showSpinner() {
self.view.bringSubviewToFront(self.actvIndicator)
self.actvIndicator.startAnimating()
}
The problem here stands on the fact that table view is draw after you are calling self.view.bringSubviewToFront(self.actvIndicator). A possible workaround for this is to call bringSubviewToFront when showing the spinner
func showSpinner(){
self.view.bringSubviewToFront(self.actvIndicator)
self.actvIndicator.startAnimating()
}

Resources