I got the problem that I'm loading a local html file in a WKWebview.
My procedure is working for iOS 8, 9, 11 but not for 10.3. There is just white space in the middle of the text.
I'm creating my WKWebview like this:
let webConfiguration = WKWebViewConfiguration();
let frame = CGRect(x: 0, y: 0, width: cell.frame.width, height: self.webViewHeight);
infoWebView = WKWebView(frame: frame, configuration: webConfiguration);
infoWebView.navigationDelegate = self;
infoWebView.translatesAutoresizingMaskIntoConstraints = false
infoWebView.scrollView.isScrollEnabled = false;
infoWebView.clipsToBounds = false;
infoWebView.allowsBackForwardNavigationGestures = false
infoWebView.contentMode = .scaleToFill
infoWebView.sizeToFit()
The loading of my html file is done by the following code:
if let availableUrl = url {
let urlRequest = URLRequest(url: availableUrl)
infoWebView.load(urlRequest)
}
Do you have an idea why it's working for iOS 8,9,11 but not for iOS 10.3?
Can somebody reproduce this problem?
Kind regards and have a nice day!
Since I had my wkwebview in a table view I had to override scrollViewDidScroll from UITableViewDelegate.
this code from WKWebView not rendering correctly in iOS 10 did the trick for me:
// in the UITableViewDelegate
func scrollViewDidScroll(scrollView: UIScrollView) {
if let tableView = scrollView as? UITableView {
for cell in tableView.visibleCells {
guard let cell = cell as? MyCustomCellClass else { continue }
cell.webView?.setNeedsLayout()
}
}
}
Related
I am using a UICollectionViewController to display cells with content loaded from an external JSON api. To be specific, these cells include UILabels for the user that posted the video, the title of the video, etc.
In addition to the text labels, there is a large UIView in the middle of the cell to play video.
The following is the code for my UICollectionViewCell.
class PostCell : UICollectionViewCell {
var videoCell: VideoPlayerView
let storyTitleLabel: UILabel = {
let storyTitleLabel = UILabel()
storyTitleLabel.translatesAutoresizingMaskIntoConstraints = false
return storyTitleLabel
}()
let usernameLabel: UILabel = {
let usernameLabel = UILabel()
usernameLabel.translatesAutoresizingMaskIntoConstraints = false
return usernameLabel
}()
func prepare(post: ApiPost) {
self.usernameLabel.text = post.user?.username
self.postTitleLabel.text = post.title!
self.storyTitleLabel.text = post.story?.title
self.videoCell.prepare(post: post)
}
func focus() {
self.videoCell.focus()
}
func unfocus() {
self.videoCell.unfocus()
}
}
When a user is scrolling through the UICollectionView and the middle of the screen is over the visible UICollectionViewCell, the focus method is called.
This loads up the video corresponding to the ApiPost (api data wrapper) for that UICollectionViewCell.
I have also programmed my own subclass of UIView for the videoCell as you can see. The following is the source code of that class.
class VideoPlayerView: UIView {
func prepare(post: ApiPost) {
self.post = post
self.videoUrl = sharedConfig.apiUrl + "/stream/" + post.video!.uuid! + ".mp4"
if let url = URL(string: self.videoUrl!) {
let avPlayerItem = AVPlayerItem(url: url)
if (self.hasReceivedApiData) {
DispatchQueue.global(qos: .background).async {
print("inserting...")
self.player?.replaceCurrentItem(with: avPlayerItem)
print("done")
}
} else {
self.hasReceivedApiData = true
self.player = AVQueuePlayer.init()
self.player?.automaticallyWaitsToMinimizeStalling = false
self.player?.insert(avPlayerItem, after: nil)
self.player?.volume = 1
let playerLayer = AVPlayerLayer(player: self.player)
playerLayer.frame = CGRect(x: 0, y: -70, width: self.frame.width - 32, height: self.frame.height)
self.layer.addSublayer(playerLayer)
}
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem, queue: nil, using: { (_) in
DispatchQueue.main.async {
self.player?.seek(to: kCMTimeZero)
self.player?.play()
}
})
}
}
func focus() {
self.player?.volume = 1.0
self.player?.play()
}
func unfocus() {
self.player?.seek(to: kCMTimeZero)
self.player?.pause()
}
}
The problem that I am having is that when I scroll over the UICollectionView, it lags really badly when prepare() is called on a reused UICollectionViewCell. It seems that calling self.player?.replaceCurrentItem(with: avPlayerItem) is slowing the UI down on scroll. I have verified this by putting the print calls between. It seems this is a slow operation that is lagging the UI, as you can see, I even tried putting that operation on a different thread, but no luck.
Am I displaying video properly in a UICollectionViewCell? Should I be doing this using some other method? The only way I could figure out to clear the old video is by using an AVQueuePlayer to clear out old AVPlayerItems, and insert the new AVPlayerItem when the cell is reused and prepared for the next video.
Any help on this would be greatly appreciated! Thanks in advance.
I have set up my UITableView to use the new Drag and Drop APIs.
if #available(iOS 11, *) {
self.tableView.dragDelegate = self
self.tableView.dropDelegate = self
self.tableView.dragInteractionEnabled = true
navigationController?.navigationBar.prefersLargeTitles = false
}
Now, I implemented the method below to be able to use custom views for the d&d.
#available(iOS 11.0, *)
func dragInteraction(_ interaction: UIDragInteraction, previewForLifting item: UIDragItem, session: UIDragSession) -> UITargetedDragPreview? {
print("Custom Preview method called!")
let test = UITextView.init(frame: CGRect.init(x: 0, y: 0, width: 200, height: 200))
test.text = "sfgshshsfhshshfshsfh"
let dragView = interaction.view!
let dragPoint = session.location(in: dragView)
let target = UIDragPreviewTarget(container: dragView, center: dragPoint)
return UITargetedDragPreview(view: test, parameters:UIDragPreviewParameters(), target:target)
}
However, this method never gets called. I never see the print() or my custom view. Any ideas as to what I'm doing wrong?
You have to set previewProvider property when creating the UIDragItem.
let dragItem = UIDragItem(...)
dragItem.previewProvider = {
print("Custom Preview method called!")
let test = UITextView.init(frame: CGRect.init(x: 0, y: 0, width: 200, height: 200))
test.text = "sfgshshsfhshshfshsfh"
return UIDragPreview(view: test)
}
See: https://developer.apple.com/documentation/uikit/uidragitem/2890972-previewprovider?language=objc
Are you using an iPhone? I am not certain it is currently working for customer UIViewController as of November 25, 2017 based on the following:
I downloaded the Apple sample project for drag-and-drop on an iPad
I added a breakpoint in dragInteraction and confirmed I could reach it
I modified the target to be a universal app (i.e. iPhone, too)
I ran on an iPhone 8 device and did not reach the breakpoint
As further suggestion, there is a property named dragInteractionEnabled for both UITableViewController and UICollectionViewController. For iPhone devices, the property is defaulted to false and, more importantly, the property is not even defined higher in UIViewController.
Alright, like everyone Im new to ms stickers in Swift but I am trying to figure out the purpose of / difference between an mssticker and msstickerview. I have read the API here https://developer.apple.com/reference/messages/msstickerview/1648434-sticker but cant find an answer to this relatively simple problem - it seems you can only add MSStickers (not StickerViews) to an MSStickerBrowserView, which is the only way to display them. I however need to add StickerVIEWS because I have a custom sticker view class I am trying to implement.
My stickers are added to my browser view here:
func loadStickers() {
var url: URL?
var i = 1
while true {
url = Bundle.main.url(forResource: "test\(i)", withExtension: "png") //change test for packs
print("URL IS THIS: \(url)")
guard let url = url else { break }
//make it a sticker
let sticker = try! MSSticker(contentsOfFileURL: url, localizedDescription: "")
let stickerView = InstrumentedStickerView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
stickerView.sticker = sticker
stickerView.delegate = self
stickerViews.append(stickerView)
stickers.append(sticker)
i += 1
}
}
func createStickerBrowser() {
let controller = MSStickerBrowserViewController(stickerSize: .regular)
addChildViewController(controller)
view.addSubview(controller.view)
controller.stickerBrowserView.backgroundColor = UIColor.white
controller.stickerBrowserView.dataSource = self
//resize this programmatically later
view.topAnchor.constraint(equalTo: controller.view.topAnchor).isActive = true
view.bottomAnchor.constraint(equalTo: controller.view.bottomAnchor).isActive = true
view.leftAnchor.constraint(equalTo: controller.view.leftAnchor).isActive = true
view.rightAnchor.constraint(equalTo: controller.view.rightAnchor).isActive = true
}
As you can see, I am creating both a sticker and a sticker view for each sticker - my stickers are stored in the stickers array and sticker views in stickerViews array.
Here is how the browser is populated:
func numberOfStickers(in stickerBrowserView: MSStickerBrowserView) -> Int {
return stickers.count
}
func stickerBrowserView(_ stickerBrowserView: MSStickerBrowserView, stickerAt index: Int) -> MSSticker {
return stickers[index] //this isnt displaying stickerveiws only stickers
}
I have tried changing the return type on these methods to StickerView and returning the stickerView array instead
func stickerBrowserView(_ stickerBrowserView: MSStickerBrowserView, stickerAt index: Int) -> MSStickerView {
return stickerViews[index] //this isnt displaying stickerveiws only stickers
}
however this gets me the following error:
messagesviewcontroller does not conform to protocol
msstickerbrowserviewdatasource
Because the required function isn't being implemented as it was before. How does one display sticker views? What am I doing wrong?
You cannot add MSStickerViews to MSStickerBrowserView. In order to use your subclass, you will have to build your own interface per Apple's documentation for MSStickerBrowserView:
If you need additional customizations, you must build your own user interface using MSStickerView objects.
If you want to emulate the look of the browser view, you can just use a UICollectionView and populate the cells with your sticker views
I want to copy one UIView to another view without making it archive or unarchive.
Please help me if you have any solution.
I tried with by making an extension of UIView as already available an answer on Stack over flow. But its crashing when I pass the view with pattern Image Background color.
The code related to my comment below:
extension UIView
{
func copyView() -> UIView?
{
return NSKeyedUnarchiver.unarchiveObjectWithData(NSKeyedArchiver.archivedDataWithRootObject(self)) as? UIView
}
}
I've just tried this simple code in a Playground to check that the copy view works and it's not pointing the same view:
let originalView = UIView(frame: CGRectMake(0, 0, 100, 50));
originalView.backgroundColor = UIColor.redColor();
let originalLabel = UILabel(frame: originalView.frame);
originalLabel.text = "Hi";
originalLabel.backgroundColor = UIColor.whiteColor();
originalView.addSubview(originalLabel);
let copyView = originalView.copyView();
let copyLabel = copyView?.subviews[0] as! UILabel;
originalView.backgroundColor = UIColor.blackColor();
originalLabel.text = "Hola";
originalView.backgroundColor; // Returns black
originalLabel.text; // Returns "Hola"
copyView!.backgroundColor; // Returns red
copyLabel.text; // Returns "Hi"
If the extension wouldn't work, both copyView and originalView would have same backgroundColor and the same would happen to the text of the labels. So maybe there is the possibility that the problem is in other part.
Original Post
func copyView(viewforCopy: UIView) -> UIView {
viewforCopy.hidden = false //The copy not works if is hidden, just prevention
let viewCopy = viewforCopy.snapshotViewAfterScreenUpdates(true)
viewforCopy.hidden = true
return viewCopy
}
Updated for Swift 4
func copyView(viewforCopy: UIView) -> UIView {
viewforCopy.isHidden = false //The copy not works if is hidden, just prevention
let viewCopy = viewforCopy.snapshotView(afterScreenUpdates: true)
viewforCopy.isHidden = true
return viewCopy!
}
I am writing a app in Swift where I am trying to load a preview of images using iCarousel of html pages for which I am using UIWebView.
Now the problem I have is I am unable to preview html pages, however when I trying to preview images, I am able to preview it.
Here is my code
func carousel(carousel: iCarousel, viewForItemAtIndex index: Int, reusingView view: UIView?) -> UIView {
var webView : UIImageView!
let webV:UIWebView = UIWebView(frame: CGRectMake(0, 0, 200, 200))
webV.loadRequest(NSURLRequest(URL: NSURL(string: "http://www.google.com")!))
webV.contentMode = .ScaleAspectFit
if webView == nil{
webView = UIImageView(frame:CGRect(x:0,y:0,width:200,height:200))
webView.contentMode = .ScaleAspectFit
}else{
webView = view as! UIImageView
}
webView.image = UIImage(named:"left-arrow.png")!
return webView //returns image carousel
//return webV //returns blank carousel. I want this to work !!!
}
How do I achieve this functionality ?
Edit 1
I can preview images for
carousel.type = iCarouselType.Linear screen attached.
This is how it looks
but I want it for any other carousel, say
carousel.type = iCarouselType.CoverFlow this is what I get
This is what I get when I am returning UIImageView
I have achieved this functionality by using WKWebView instead of UIWebView
Here is the working code
let webV:WKWebView!
webV = WKWebView(frame: CGRectMake(20, 20, 200, 200))
var url = NSURL(string:"http://www.fb.com/")
var req = NSURLRequest(URL:url!)
webV!.loadRequest(req)
return webV
Also,make sure you have imported WebKit by adding the below line
import WebKit