I am having auto layout issues with an embed YouTube video. In fact Apple have just rejected the App I have sent them on these grounds. This is the code that I have submitted.
import UIKit
class ImproveViewController: UIViewController {
#IBOutlet weak var videoView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
let youTubeUrl = "https://www.youtube.com/embed/NpepI1dtIz8"
videoView.allowsInlineMediaPlayback = true
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.videoView.loadHTMLString("<iframe width=\"\(self.videoView.frame.width)\" height=\"\(self.videoView.frame.height)\" src=\"\(youTubeUrl)\" frameborder=\"0\" allowfullscreen></iframe>", baseURL: nil)
print("This is run on the main queue, after the previous code in outer block")
})
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
This what is looks like when I run in the simulator.
How can this be fixed? Any help will be greatly appreciated. I have added the Web View constraints to the entire screen. Thanks again for your help.
Your code look okay and I have tested it. I think you have problem in constraints.
Just add Top, Bottom, Leading and trailing constraints with constants = 0 to superview
Related
In a UIWebview I want to change
<iframe src=“//player.vimeo.com/video/164231311?autoplay=1” width=“700" height=“394” frameborder=“0" webkitallowfullscreen=“” mozallowfullscreen=“” allowfullscreen=“”></iframe>
to
<iframe src=“//player.vimeo.com/video/164231311" width=“700” height=“394" frameborder=“0” webkitallowfullscreen=“” mozallowfullscreen=“” allowfullscreen=“”></iframe>
since I want the user to be presented with a play button instead of a pause button since autoplay is not allowed on iOS. It'll be more natural for the user to see a play button directly instead of the pause button as in the image below.
How do I do that in a simple way? I’ve tried some stuff like
webView.stringByEvaluatingJavaScript(from:“document.getElementsByTagName(…)
without success so far.
Here I made rough demo code to solve your issue. Put your logic with that and it will solve your issue.
It was tested and had seems working perfectly.
import UIKit
class ViewController: UIViewController,UIWebViewDelegate {
#IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
webView.delegate = self
webView.loadRequest(URLRequest(url: URL(string: "file:///Users/user/Downloads/index.html")!))
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func webViewDidFinishLoad(_ webView: UIWebView) {
// get your current iframe src value
let iframeSrcValue:String = webView.stringByEvaluatingJavaScript(from: "document.getElementsByTagName('iframe')[0].src")!
// Here is your current value with AutoPlay
print(iframeSrcValue)
//Create new URL without Auto Play
let modifiedSrcValue = "https://www.youtube.com/embed/td8pYyuCIIs"
// Apply it to webview
let evaluate: String = "document.getElementsByTagName('iframe')[0].src='\(modifiedSrcValue)';"
webView.stringByEvaluatingJavaScript(from: evaluate)
}
}
I still don't understand how I should get the updated frame of a UIView, when using autolayout.
Let's say I:
Setup some views using autolayout.
Make an HTTP request to get some data.
When I get the data, I want to draw it but I need the updated frame size of a view.
How should I go about it?
My guess, but it's wrong:
layoutMyViews()
makeHttpRequest(callback)
func callback(data: MyData) {
drawData(data, into:dataView)
}
func drawData(data: MyData, into view:UIView) {
let size = view.frame.size
// Here I want to draw data into view, depending on size, but it may be (0,0)
}
Here's just an example UIViewController - you can start your call in view did load and block the ui or at least indicate activity and then when that call completes you can update the UI based off of whatever current view properties you'd like.
class ViewController: UIViewController {
// You can start accessing view properties from the storyboard here.
override func viewDidLoad() {
super.viewDidLoad()
print(self.view.frame) // Outputs the frame of the view controller's view.
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidLayoutSubviews() {
}
override func viewWillAppear(animated: Bool) {
}
override func viewDidAppear(animated: Bool) {
}
}
This is more or less what I'm doing right now. If anyone can suggest a better alternative please post or comment about it.
As you will see, in drawDataIfPossible() I check that both the data is set and the frame size is set. I check both because drawDataIfPossible() is called from these two functions:
drawData(data: MyData), which might be called before the frame size is set
layoutSubviews(), which might be called before the data is set.
.
class Controller : UIViewController {
// Here I will draw some data that comes from server
var dataView: MyDataView!
override func viewDidLoad() {
super.viewDidLoad()
// Here I add the views using autolayout, including dataView
layoutMyViews()
// Here I make the http request to get data
makeHttpRequest(callback)
}
/** When the data comes, I tell the dataView to draw itself */
func callback(data: MyData) {
dataView.drawData(data)
}
//...
}
class MyDataView : UIView {
var data: MyData!
/** Draws the data in the view */
func drawData(data: MyData) {
self.data = data
drawDataIfPossible()
}
func drawDataIfPossible() {
// Here I check I have the data and that the frame size is set
if data != nil && frame.size.width > 0 {
drawData()
}
}
/** Draws data in the view (needs the frame size) */
func drawData {
// ...
}
override func layoutSubviews()
{
super.layoutSubviews()
layoutIfNeeded() // seems to be necessary for the frame size to be set
drawDataIfPossible()
}
}
I am working on an application that has different UI constraints and control positions for portrait and landscape. These are all done on the storyboard. In addition to this, I am repositioning controls based on a user shutting off one of the controls. I am doing this by grabbing the frame for each of the controls in viewDidLoad. Once I have these values, then it is easy to reposition the controls and restore them to what they should be when unhidden. The thing is that I need all of the frames for both portrait and landscape. That way I can do the repositioning regardless of orientation.
How can I get the control positioning information for both portrait and landscape when coming through viewDidLoad? Is there any way to do this?
After adding constraints to a view, and the view readjusting its position and size according to device size and orientation. This readjusting of the view size is done in the method viewDidLayoutSubviews, which is called after viewDidAppear.
If you can log out the positions and size of the control in this method, you will get the updated (size and position as it is seen in the device).
But this method is called multiple times after viewDidAppear, so if you want to add anything i recommend adding the control in viewDidLoad and then updating the position in this method.
After working with this a bit more, I came up with this:
import UIKit
class ViewController: UIViewController {
var pButtonFrame: CGRect!
var lButtonFrame: CGRect!
#IBOutlet weak var testButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
NSNotificationCenter.defaultCenter().addObserver(self, selector: "screenRotated", name: UIDeviceOrientationDidChangeNotification, object: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func screenRotated() {
//Set this only once, the first time the orientation is used.
if lButtonFrame == nil && UIDeviceOrientationIsLandscape(UIDevice.currentDevice().orientation)
{
lButtonFrame = testButton.frame
}
else if pButtonFrame == nil && UIDeviceOrientationIsPortrait(UIDevice.currentDevice().orientation)
{
pButtonFrame = testButton.frame
}
}
}
I set up a test button and positioned it using constraints on the storyboard. I added an observer to NSNotificationCenter to watch for screen rotation. I'm storing the frames for each of the orientations in CGRect variables. By checking each of the variables for nil, I can ensure that they only get set once, before I have done any modifications to the screen. That way, I can restore the values to their originals, if needed. I can set up the showing and hiding of controls here, or in viewDidLayoutSubviews.
import UIKit
class ViewController: UIViewController {
var pButtonFrame: CGRect!
var lButtonFrame: CGRect!
#IBOutlet weak var btntest: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
screenRotate()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func screenRotate() {
//Set this only once, the first time the orientation is used.
if lButtonFrame == nil && UIDeviceOrientationIsLandscape(UIDevice.currentDevice().orientation)
{
lButtonFrame = btntest.frame
}
else if pButtonFrame == nil && UIDeviceOrientationIsPortrait(UIDevice.currentDevice().orientation)
{
pButtonFrame = btntest.frame
}
}
}
I just want to modify the height of a UITextView.
The log resulting from the code below, says that in fact, the
height changed from 30 to 400:
println(txtresponses.frame.height) // returns 30
var newFrame:CGRect=txtresponses.frame
newFrame.size.height=400
txtresponses.frame=newFrame
println(txtresponses.frame.height) // returns 400
However, visually, the UITextView "txtresponses" remains with the same size.
I am new to Swift and Xcode, so all my tricks are already exhausted here, and I dont know if it is an iOS version issue, or some typical Xcode whim.
What is the correct way to modify a UITextView ´s height?
Make sure to call txtresponses.frame=newFrame in the main thread.
dispatch_async(dispatch_get_main_queue()) {
txtresponses.frame=newFrame
}
All UI updates must be done from the main thread.
Its not work because I think you are using Autolayout with constraint. Please check below url which may help you - Change height constraint programmatically
Might be issue Autolayout. u just remove the autolayout and check it will work. Check below code i hope it will help you.
Example :
import UIKit
class ViewController: UIViewController {
#IBOutlet var textView: UITextView!
#IBOutlet var butt: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
textView.backgroundColor = UIColor.lightGrayColor()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func buttonAction(sender: UIButton) {
var newFrame:CGRect=textView.frame
newFrame.size.height=400
textView.frame=newFrame
}
}
Screen 1:
Screen 2:
I wanna display a couple of images from the assets folders, into my application. so I wanna make a page view.
First, images will be inside collection view, then on click, the image will be full screen. Then the user can slide between the images by swiping right and left as shown in the following photo:
I found this tutorial:
PhotosGalleryApp
Updated:
I have this in my storyboard:
Now in GaleryViewController I show the images in cells
when user click on it, I open the image in fullscreen in PhotoViewController.
PhotoViewController.swift :
import UIKit
class PhotoViewController: UIViewController{
#IBOutlet weak var imageView: UIImageView!
var index: Int = 0;
var pageViewController : UIPageViewController?
#IBAction func btnCancelClicked(sender: AnyObject) {
self.navigationController?.popToRootViewControllerAnimated(true);
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
initUI();
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(animated: Bool) {
self.navigationController?.hidesBarsOnTap = true;
self.navigationController?.hidesBarsOnSwipe = true;
displayPhoto()
}
func initUI() -> Void {
// pageViewController = UIPageViewController(transitionStyle: .Scroll, navigationOrientation: .Horizontal, options: nil)
// pageViewController!.dataSource = self
}
func displayPhoto() {
self.imageView.image = UIImage(named: Constants.Statics.images[index])
}
I have the images in static structure so i can access them anywhere:
class Constants {
struct Statics {
static let images = ["1.jpg","2.jpg","3.jpg","4.jpg","5.jpg","7.jpg","8.jpg"]
}
}
My problem is: I want to add the feature that allow me to swipe between pictures inside the PhotoViewController.
Any ideas?
Thank you
You can do one of the following two things to achieve your goal :
Make a modal segue of the cell to the next UICollectionViewController where the images are showed in full screen, and in the prepareForSegue pass all the data (images) you need to show and where exactly you are in this moment (indexOfImage).
You can watch the didSelectItemAtIndexPath and then pass all the data to one instance of the next UICollectionViewController you want to show with the presentViewController func.
But it's very important that in the next UICollectionViewController you have set pageEnabled = true in code or in the Interface Builder (I though is much easy to do.)
UPDATE:
Very good tutorials on how to make a slide show of images using an UIScrollView or an UICollectionView :
How To Use UIScrollView to Scroll and Zoom Content
Creating a Paged Photo Gallery With a UICollectionView
I hope this help you.