Animate the the text in a textview (swift3) - ios

I am looking for the text to be scroll all the way down to the bottom that is it. Just like you would see in movie credits. I do not want to move the x, y location of the textview just the text inside from top to bottom.
import UIKit
class ViewController: UIViewController {
#IBOutlet var text: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func play(_ sender: Any) {
}
}

Use a UIScrollView and scroll a UILabel with the text in it.
You can use standard UIView animation with timing and optionally animation curve and set the contentOffset inside the closure.
UIView.animate(withDuration: 10.0) { // 10 seconds
scrollView.contentOffset = CGPoint(x: 0, y: maxDesiredScrollPosition)
}

Related

I want to scroll every thing except button in view

I am using scroll view which scrolling everything perfectly but i have button at the top of view for dissmissing view i want it to remain there and do not scroll in swift .
Add first UIScrollView and then UIButton to self.view.
Add button outside scrollview content like overlay.
Try this solution:
class TmpVC: UIViewController, UIScrollViewDelegate {
#IBOutlet var scoll : UIScrollView!
#IBOutlet var btn : UIButton!
var btnPoint : CGPoint!
override func viewDidLoad() {
super.viewDidLoad()
scoll.contentSize = CGSize(width: 320, height: 600)
scoll.delegate = self
btnPoint = btn.frame.origin
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
btn.frame.origin = CGPoint(x: btnPoint.x, y: btnPoint.y + scrollView.contentOffset.y)
}
deinit {
print("deinit Tmpvc")
}
}

UIWebView delegates don't fire in a custom class

I spent around 5 hours searching on StackOverFlow about how to implement this and I still not found a solution yet!
I have created a new iOS Swift app just to explain you what exactly I am trying to resolve.
First, I have a UIButton on main storyboard and when you click on it, it creates a new object from class WebViewAsPopup which creates programmatically a new WebView and a background as UIView with alpha 0.5, add some styling and then it add them to the main view controller ViewController as a popup.
Secondly, I couldn't set a delegate to those WebView's to handle UIWebViewDelegate and listen to both webViewDidStartLoad and webViewDidFinishLoad
Here's my code:
ViewController.swift
//
// ViewController.swift
// MySimpleApp
//
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var showPopupBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func showPopupTapped(_ sender: Any) {
let popup = WebViewAsPopup()
popup.showWebViewPopup(on: self)
}
}
WebViewAsPopup.swift
//
// WebViewAsPopup.swift
// MySimpleApp
//
import WebKit
class WebViewAsPopup: NSObject, UIWebViewDelegate {
func showWebViewPopup(on controller: UIViewController) {
// Popup background
let bg = UIView()
bg.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
bg.layer.backgroundColor = UIColor.black.withAlphaComponent(0.5).cgColor
// Webview sizing
let width = UIScreen.main.bounds.width - 60
let height = UIScreen.main.bounds.height - 200
let x = UIScreen.main.bounds.width/2 - width/2
let y = UIScreen.main.bounds.height/2 - height/2
// Webview stuff
let webView = UIWebView()
webView.frame = CGRect(x: x, y: y, width: width, height: height)
let url = URL(string: "https://google.com")
let request = URLRequest(url: url!)
// webView.delegate = self << it crash here
webView.loadRequest(request)
// Styling webview popup
webView.layer.borderWidth = 1
webView.layer.borderColor = UIColor.black.cgColor
webView.layer.masksToBounds = true
webView.layer.cornerRadius = 10
// Add bg then webview to main view controller
controller.view.addSubview(bg)
controller.view.addSubview(webView)
}
func webViewDidStartLoad(_ webView: UIWebView)
{
print("#webViewDidStartLoad!") // << it doesn't fire :(
}
func webViewDidFinishLoad(_ webView: UIWebView)
{
print("#webViewDidFinishLoad!") // << it doesn't fire :(
}
}
As I noted in my comments, you need to save the popup object somewhere in order to retain it. If not (as in your example code), then it will be deallocated as soon as the action method showPopupTapped(_:) is completed.
Try this:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var showPopupBtn: UIButton!
let popup = WebViewAsPopup()
#IBAction func showPopupTapped(_ sender: Any) {
self.popup.showWebViewPopup(on: self)
}
}
Bonus Note:
If you're wondering why you don't need to do the same to the background view and web view in your popup object, that's because views automatically retain their subviews.
So, once you add your background view and web view as subviews to a parent view, their retain count goes up and will survive their current scope.

Swift viewDidLoad() in second View Controller Scene not working

I'm a beginner at swift and Xcode, so this question may sound very simple.
I have two view controllers, connected by a segue. My first view controller scene runs code from the viewDidLoad() function, and then calls the .performSegue() function for the second view controller scene to get displayed.
But now, I want to run code in that new .swift file. viewDidLoad() doesn't seem to work, so how do I get around this problem? Where else could I put my code, or what function should it be in?
EDIT
// Show main menu
self.performSegue(withIdentifier: "MenuSegue", sender: self)
is how I am switching between view controllers. The buttons display, but anything I write in viewDidLoad() does not work
EDIT 2
My code for ViewController.swift:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var startScreen: UIStackView! // H2O start screen
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Display start screen for 2 seconds before fading out
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2, execute: {
// Fade out start screen
UIView.animate(withDuration: 1, animations: {self.startScreen.alpha = 0})
// Wait 1 second from when start screen starts to fade out
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1, execute: {
// Show main menu
self.performSegue(withIdentifier: "MenuSegue", sender: self)
})
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
And for MenuViewController.swift:
import UIKit
class MenuViewController: UIViewController {
#IBOutlet weak var playButton: UIButton! // Play button
#IBOutlet weak var settingsButton: UIButton! // Settings button
#IBOutlet weak var volumeButton: UIButton! // Volume button
#IBOutlet weak var volumeStack: UIStackView! // Volume stack
#IBOutlet weak var volumePercentage: UILabel! // Volume percentage
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
print("Hello")
// Slowly display everything
playButton.alpha = 0
settingsButton.alpha = 0
volumeButton.alpha = 0
volumeStack.alpha = 0
// Fade out start screen
UIView.animate(withDuration: 1, animations: {self.playButton.alpha = 1; self.settingsButton.alpha = 1; self.volumeButton.alpha = 1; self.volumeStack.alpha = 1})
print("Hi")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func settings(_ sender: UIButton) {
// If the settings are hidden
if volumeButton.alpha == 0 {
// Rotate settings button to open settings
UIView.animate(withDuration: 0.5, animations: {sender.transform = CGAffineTransform(rotationAngle: .pi * -0.999)})
// Show extended settings
UIView.animate(withDuration: 0.5, animations: {self.volumeButton.alpha = 1})
}
else {
// Rotate settings button back to normal
UIView.animate(withDuration: 0.5, animations: {sender.transform = CGAffineTransform(rotationAngle: 0.0)})
// Hide extended settings
UIView.animate(withDuration: 0.5, animations: {self.volumeButton.alpha = 0})
}
}
#IBAction func volumeSlider(_ sender: UISlider) {
// Get slider value rounded to nearest 5
let value = round(sender.value / 5) * 5
// Set the value to nearest 5
sender.value = value
// Show volume percentage
volumePercentage.text = "\(Int(value))%"
}
#IBAction func playButton(_ sender: UIButton) {
// Hide all settings
settingsButton.alpha = 0
volumeButton.alpha = 0
volumeStack.alpha = 0
// Hide play button
sender.alpha = 0
}
}
Add your animation code inside viewWillAppear() method.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Add animation code here
}

Repeat animation from left to right smoothly

I'm trying to animate 3 squares from the left to the right. The squares should reappear from the left while they are disappearing from the right. The idea is that the squares represent clouds, so the idea is clear.
This is what I currently got:
class ViewController: UIViewController {
// contains the squares
#IBOutlet weak var containerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
startAnimating()
}
func startAnimating() {
UIView.animateKeyframes(withDuration: 10, delay: 0, options: .repeat, animations: {
self.containerView.center.x += self.view.bounds.width
}, completion: nil)
}
}
This is the result:
The squares move from the left to the right. This is good. The problem is that once the animation is done the squares just reappear from where they started. It isn't a smooth continuous movement where the clouds move from the left to the right and slowly reappear from the left again. How do you achieve this? Should there be a second containerView? Or remove the containerView and animate individual clouds?
The answer Milan Nosáľ solved the problem. A note though:
I placed containerView2 above containerView1 with the exact same
constraints (they overlap each other). Just make sure IB doesn't
include containerView2 as a subview of containerView1.
I guess the simplest approach for you know is to use two exactly the same containers. You can use exactly the same code, and put the containerView2 above containerView to make sure that cover one another.
And then simply use:
class ViewController: UIViewController {
// contains the squares
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var containerView2: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// this will transform the containerView2 to the left to appear as if it was exactly to the left of the containerView
containerView2.transform = CGAffineTransform.identity.translatedBy(x: -self.view.bounds.width, y: 0)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
startAnimating()
}
func startAnimating() {
UIView.animateKeyframes(withDuration: 10, delay: 0, options: .repeat, animations: {
self.containerView.center.x += self.view.bounds.width
self.containerView2.center.x += self.view.bounds.width
}, completion: nil)
}
}
The containerView2 will represent the clouds coming back from the left.
You could try something like putting containerView.center.x -= 200 right before starting the animation. This way it first appears from the left side.

How to resize ScrollView when keyboard appears?

I'm trying to create this post feature which would allow you to insert text as well as images (similar to Note app on iOS devices). However, I can't figure out how to move or resize my ScrollView when the keyboard appears when I press on the light-grey area (it's a text view field), so the grey area would resize and the add button would move above the keyboard when it appears.
// PostViewController.swift
//
// Created by Martynas on 09/12/2016.
// Copyright © 2016 Martynas. All rights reserved.
//
import UIKit
import Firebase
class PostViewController: UIViewController, UITextFieldDelegate {
#IBOutlet var ScrollView: UIScrollView!
#IBOutlet var titleTextField: UITextField!
#IBOutlet var contentTextField: UITextView!
#IBOutlet var Menu: UIView!
#IBAction func hideKeyboardWhenSwippedDown(_ sender: Any) {
contentTextField.endEditing(true)
}
override func viewDidLoad() {
super.viewDidLoad()
// Hide keyboard when...
self.hideKeyboardWhenTappedAround() // ...press anywhere outside the keyboard
self.titleTextField.delegate = self
self.contentTextField.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func sendTapped(_ sender: Any) {
if let uid = FIRAuth.auth()?.currentUser?.uid {
if let title = titleTextField.text {
if let content = contentTextField.text {
let postObject: Dictionary<String, Any> = [
"uid": uid,
"title": title,
"content": content
]
FIRDatabase.database().reference().child("posts").childByAutoId().setValue(postObject)
}
}
}
}
#IBAction func addTapped(_ sender: Any) {
}
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == contentTextField {
ScrollView.setContentOffset(CGPoint(x: 0, y: 0), animated: true)
} else {
return
}
}
func textFieldDidEndEditing(_ textField: UITextField) {
if textField == contentTextField {
ScrollView.setContentOffset(CGPoint(x: 0, y: 250), animated: true)
} else {
return
}
}
// Hide keyboard when user presses 'return' key on the keyboard...
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
titleTextField.resignFirstResponder()
return true
}
}
This is the Controller View:
You need to listen to the keyboardDidShow/Hide notification and adjust the scroll view's height accordingly. The keyboardDidShow notification userInfo contains the keyboard's frame and therefore height.
Presuming your scroll view has a constraint at the bottom of the super view, you can make it an IBOutlet and animate it's constant to the height of the keyboard and back to 0 when the keyboard show and hide notifications are fired respectively.

Resources