Animation only works on one button (ripple view) - swift

Site used: https://material.io/develop/ios/components/ripple/
Here is my code:
import MaterialComponents.MaterialRipple
class ViewController: UIViewController {
// let rippleView = MDCRippleView()
let rippleTouchController = MDCRippleTouchController()
#IBOutlet weak var playBtn: UIButton!
#IBOutlet weak var levelsBtn: UIButton!
#IBOutlet weak var topicsBtn: UIButton!
#IBOutlet weak var settingsBtn: UIButton!
#IBOutlet weak var instaBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
//This works for instabtn (lastone)
// rippleTouchController.rippleView.rippleColor = .lightGray
// rippleTouchController.addRipple(to: playBtn)
// rippleTouchController.addRipple(to: levelsBtn)
// rippleTouchController.addRipple(to: topicsBtn)
// rippleTouchController.addRipple(to: settingsBtn)
// rippleTouchController.addRipple(to: instaBtn)
}
override func viewDidAppear(_ animated: Bool) {
// Currently only works for playbtn
rippleTouchController.rippleView.rippleColor = .lightGray
rippleTouchController.addRipple(to: levelsBtn)
rippleTouchController.addRipple(to: topicsBtn)
rippleTouchController.addRipple(to: settingsBtn)
rippleTouchController.addRipple(to: instaBtn)
rippleTouchController.addRipple(to: playBtn)
}
}
I've tried to put the code in viewDidAppear but it doesn't make a difference. Any thoughts?

Foreach button you have to create a MDCRippleTouchController.
let rippleTouchController = MDCRippleTouchController()
let rippleTouchController2 = MDCRippleTouchController()
let rippleTouchController3 = MDCRippleTouchController()
let rippleTouchController4 = MDCRippleTouchController()
let rippleTouchController5 = MDCRippleTouchController()
override func viewDidAppear(_ animated: Bool) {
rippleTouchController.rippleView.rippleColor = .lightGray
rippleTouchController.addRipple(to: levelsBtn)
rippleTouchController2.addRipple(to: topicsBtn)
rippleTouchController3.addRipple(to: settingsBtn)
rippleTouchController4.addRipple(to: instaBtn)
rippleTouchController5.addRipple(to: playBtn)
}

Related

Sigbart error during prepare for segue/unwind segue

I have an app where it is a marketplace and when you click on a product, it opens a detail view controller passing the data to display on the DetailVC. Additionally, inside the DetailVC, if you click on a button to claim the product, it segues to another VC to finalize the transaction.
In the DetailVC, there is a back button which is an unwind segue back to the main marketplace VC. Inside the TransactionVC, there is a cancel button which takes you back to the DetailVC.
When I am clicking the backButton in the DetailVC to take me back to the main market VC but I am getting a SIGBART Error and this :
020-07-15 09:05:23.707490-0500 evolutionatx[707:141952] Could not cast value of type 'evolutionatx.MarketplaceViewController' (0x1032c7868) to 'evolutionatx.PopUpPurchaseViewController' (0x1032c7ba8).
Here is the code for the DetailVC
import UIKit
import iCarousel
import CoreData
class MarketDetailViewController: UIViewController, UIScrollViewDelegate, iCarouselDelegate, iCarouselDataSource {
var productImageArray = [UIImage]()
var productVideo = String()
var pointsToPurchase = String()
var productName = String()
var productDescription = String()
var companyLogo = UIImage()
var companyWebsite = String()
var additionalProductImage = [UIImage]()
var companyName = String()
var promoCODE = String()
var buyLink = String()
var slides:[Slide] = [];
//IB
#IBOutlet weak var productNameLabel: UILabel!
#IBOutlet weak var productPriceLabel: UILabel!
#IBOutlet weak var productDescLabel: UILabel!
#IBOutlet weak var claimButton: UIButton!
#IBOutlet weak var imgScrollView: UIScrollView!
#IBOutlet weak var websiteButton: UIButton!
#IBOutlet weak var pageControl: UIPageControl!
#IBOutlet weak var logoDisplay: UIImageView!
#IBOutlet weak var carouselView: iCarousel!
#IBOutlet weak var otherProductslabe: UILabel!
var carouselImages = [UIImage]()
var evoCoin = Int()
override func awakeFromNib() {
super.awakeFromNib()
carouselImages = productImageArray
}
override func viewDidLoad() {
super.viewDidLoad()
valueSetter()
imgScrollView.delegate = self
slides = createSlides()
setupSlideScrollView(slides: slides)
pageControl.numberOfPages = slides.count
pageControl.currentPage = 0
view.bringSubviewToFront(pageControl)
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
pageControl.currentPage = Int(pageIndex)
let maximumHorizontalOffset: CGFloat = scrollView.contentSize.width - scrollView.frame.width
let currentHorizontalOffset: CGFloat = scrollView.contentOffset.x
// vertical
let maximumVerticalOffset: CGFloat = scrollView.contentSize.height - scrollView.frame.height
let currentVerticalOffset: CGFloat = scrollView.contentOffset.y
let percentageHorizontalOffset: CGFloat = currentHorizontalOffset / maximumHorizontalOffset
let percentageVerticalOffset: CGFloat = currentVerticalOffset / maximumVerticalOffset
}
#IBAction func claimProduct(_ sender: Any) {
print("tap rec")
claimProductandPurchase()
}
func claimProductandPurchase(){
evoCOiner()
if(evoCoin >= Int(pointsToPurchase)!){
print("Transaction Successful")
performSegue(withIdentifier: "proceedQuestion", sender: self)
}
else{
showToast(controller: self, message: "Insufficient EvoCoins", seconds: 0.5)
}
}
func showToast(controller: UIViewController, message : String, seconds: Double) {
let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
alert.view.backgroundColor = UIColor.black
alert.view.alpha = 0.6
alert.view.layer.cornerRadius = 15
controller.present(alert, animated: true)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + seconds) {
alert.dismiss(animated: true)
}
}
func evoCoiner(){
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "EvoCoins")
request.returnsObjectsAsFaults = false
do{
let result = try context.fetch(request)
for data in result as! [NSManagedObject]
{
evoCoin = data.value(forKey: "evoCoins") as! Int
}
}catch{
print("Failed")
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let detailController = segue.destination as! PopUpPurchaseViewController
detailController.ppromo = promoCODE
detailController.link = buyLink
detailController.coinToPurchase = Int(pointsToPurchase)!
}
//This is the unwind used by the transaction back button
#IBAction func unwindToItem(segue: UIStoryboardSegue) {
}
}
Here is the code in the transaction VC
import UIKit
import AMTabView
import CoreData
class MarketplaceViewController: UIViewController, TabItem {
#IBOutlet weak var sView: UIView!
#IBOutlet weak var evoCoinLabe: UILabel!
//For the sake of simplicity I only kept the Unwind functions
//MARK: - UNWIND FUNCTIONS
#IBAction func unwindToMainMarketView(segue: UIStoryboardSegue) {
}
}
How can I fix this error?
Please advise if my question was not clear or properly phrased (if so, sorry I am pretty new to all of this)
As #matt already said in his comment and the error clearly states, you cannot cast a MarketplaceViewController to a PopUpPurchaseViewController.
Furthermore instead of doing a forced cast, always look for a safe one like below. Doing so will prevent crashes.
if let detailController = segue.destination as? PopUpPurchaseViewController {
...
}
else {
// log failed to cast
}

Crash while unwrapping an Optional Value

I am getting an error. It is returning nil on a DispatchQueue call.
DispatchQueue.main.async {
self.headerImageView.image = image // <- CRASH
}
Turns out that this is where I am getting a crash.
headerImageView is just a variable which is not connected to the storyboard via IBOutlet. Here is the entire code:
import UIKit
import WebKit
let offset_HeaderStop:CGFloat = 40.0
let offset_B_LabelHeader:CGFloat = 95.0
let distance_W_LabelHeader:CGFloat = 35.0
class MovieDetailsViewController: UIViewController, UIScrollViewDelegate {
var movie: Movie?
var urlBuilder = MovieUrlBuilder()
var config = TMDBConfiguration()
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var headerView: UIView!
#IBOutlet weak var headerLabel: UILabel!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var genreLabel: UILabel!
#IBOutlet weak var ratingLabel: UILabel!
#IBOutlet weak var releaseLabel: UILabel!
#IBOutlet weak var descriptionText: UITextView!
#IBOutlet weak var trailerContainerView: UIView!
#IBOutlet weak var trailerLabel: UILabel!
#IBOutlet weak var videoContainer: WKWebView!
var headerImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}
override func viewDidAppear(_ animated: Bool) {
headerImageView = UIImageView(frame: headerView.bounds)
headerImageView.image = UIImage(named: "Poster")
headerImageView.contentMode = .scaleAspectFill
headerView.insertSubview(headerImageView, belowSubview: headerLabel)
headerView.clipsToBounds = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
fetchPopularMovies()
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offset = scrollView.contentOffset.y
var headerTransform = CATransform3DIdentity
if offset < 0 {
let headerScaleFactor: CGFloat = -(offset) / headerView.bounds.height
let headerSizeVariation = ((headerView.bounds.height * (1.0 + headerScaleFactor)) - headerView.bounds.height)/2.0
headerTransform = CATransform3DTranslate(headerTransform, 0, headerSizeVariation, 0)
headerTransform = CATransform3DScale(headerTransform, 1.0 + headerScaleFactor, 1.0 + headerScaleFactor, 0)
headerView.layer.transform = headerTransform
} else {
headerTransform = CATransform3DTranslate(headerTransform, 0, max(-offset_HeaderStop, -offset), 0)
let labelTransform = CATransform3DMakeTranslation(0, max(-distance_W_LabelHeader, offset_B_LabelHeader - offset), 0)
headerLabel.layer.transform = labelTransform
}
headerView.layer.transform = headerTransform
}
override var preferredStatusBarStyle: UIStatusBarStyle{
return UIStatusBarStyle.lightContent
}
private func fetchPopularMovies() {
if let poster = movie?.backdropPath {
let baseURL = URL(string: config.baseImageURL)!
let url = baseURL.appendingPathComponent("w500").appendingPathComponent(poster)
let request = URLRequest(url: url)
let task = urlBuilder.session.dataTask(with: request) {(data, response, error) in
do {
if let image = UIImage(data: data!) {
DispatchQueue.main.async {
self.headerImageView.image = image // <- CRASH
}
}
}
}
task.resume()
}
}
}
Thank you for the support!
You are initializing the image view in viewDidAppear which will be called after viewWillAppear where the image view is populated. Despite the asynchronous task it's not guaranteed that the view is initialized before being populated.
I recommend to initialize the image view lazily, the benefit is that the property is non-optional and it's initialized once when it's accessed the first time.
lazy var headerImageView: UIImageView = {
let view = UIImageView(frame: self.headerView.bounds)
view.image = UIImage(named: "Poster")
view.contentMode = .scaleAspectFill
self.headerView.insertSubview(view, belowSubview: self.headerLabel)
view.clipsToBounds = true
return view
}()
Your async call is located in fetchPopularMovies, which is called at viewWillAppear. You initialise your image view in viewDidAppear, which is called after viewWillAppear.
Basically, headerImageView is nil.
"But I put the call in an async block! So viewDidAppear should have been called already when I set the image view's image, right?" you said.
Well, relying on async to say "I want this thing to run after a certain method returns" is not a good idea. It is not always guaranteed to do that.
To fix this, you need to initialise header image view before fetchPopularMovies is called. You can put it in viewDidLoad for example.

incorrect vertical navigation items alignment

I'm trying to customize Navigation bar and get it bigger with vertical alignment. Here is my code:
#IBOutlet weak var topNavTitleLabel: UILabel!
#IBOutlet weak var topNavStackView: UIStackView!
#IBOutlet weak var leftNavHomeButton: UIBarButtonItem!
#IBOutlet weak var rightNavSearchButton: UIBarButtonItem!
var rightNavSearchButton_: UIBarButtonItem?
#IBAction func searchAction(sender: UIButton) {
topNavStackView.hidden = true
topNavStackView.hidden = false
rightNavSearchButton_ = rightNavSearchButton
navigationItem.rightBarButtonItem = nil
}
#IBAction func performSearch(sender: UIButton) {
topNavStackView.hidden = false
topNavStackView.hidden = true
navigationItem.rightBarButtonItem = rightNavSearchButton_
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if let navConBar = self.navigationController?.navigationBar {
navConBar.bounds = CGRectMake(0, 0, view.bounds.width, 100)
navConBar.setTitleVerticalPositionAdjustment(-10.0, forBarMetrics: .Default)
let offset = UIOffset(horizontal: 0, vertical: -10)
navigationItem.rightBarButtonItem?.setTitlePositionAdjustment(offset, forBarMetrics: .Default)
navigationItem.leftBarButtonItem?.setTitlePositionAdjustment(offset, forBarMetrics: .Default)
}
}
When It appears it looks ok.
But When I click on right navigation bar button, left button goes to down.
Also when it turns back:
How can it be fixed?

How can I add several UIStepper Values to one Label?

I'm working right now on my first Swift project. I've got 2 stepper and one label - both stepper are sending their values to it. How can I add the value of the second stepper to the label, in which the value of the first stepper is already? Here is my code:
override func viewDidLoad() {
super.viewDidLoad()
stepper.wraps = true
stepper.autorepeat = true
stepper.maximumValue = 10000
stepper2.wraps = true
stepper2.autorepeat = true
stepper2.maximumValue = 10000
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet weak var valueLabel: UILabel!
#IBOutlet weak var stepper: UIStepper!
#IBAction func stepperValueChanged(sender: UIStepper) {
valueLabel.text = Int(sender.value).description
}
#IBOutlet weak var stepper2: UIStepper!
#IBAction func stepper2ValueChanged(sender: UIStepper) {
valueLabel.text = Int(sender.value).description
}
}
Thank you!
If you want to combine the two values to ONE String and show this String on your Label, than you have to create a new function that does this for you. I added such a function to your code:`
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
stepper.wraps = true
stepper.autorepeat = true
stepper.maximumValue = 10000
stepper2.wraps = true
stepper2.autorepeat = true
stepper2.maximumValue = 10000
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet weak var valueLabel: UILabel!
#IBOutlet weak var stepper: UIStepper!
#IBAction func stepperValueChanged(sender: UIStepper) {
// valueLabel.text = Int(sender.value).description
addValuesToASumAndPutItIntoTheLabel()
}
#IBOutlet weak var stepper2: UIStepper!
#IBAction func stepper2ValueChanged(sender: UIStepper) {
// valueLabel.text = String(sender.value)
addValuesToASumAndPutItIntoTheLabel()
}
func addValuesToASumAndPutItIntoTheLabel() {
let summe : Int = Int(stepper.value + stepper2.value)
valueLabel.text = summe.description
}
}`

Navigation Controller Error

I have a navigation controller and I want the title to have a custom font. I have tried to do this but when it runs I get Thread 1: EXC_BAD_INSTRUCTION (code=EXC_1386_INVOP.subcode=0x0)
Here is my code.
import UIKit
class PriceCheckSpreadsheetViewController: UIViewController {
#IBOutlet weak var SpreadsheetView: UIWebView!
#IBOutlet weak var Loading: UIActivityIndicatorView!
#IBOutlet weak var BackButton: UIBarButtonItem!
#IBOutlet weak var ForwardButton: UIBarButtonItem!
#IBOutlet weak var NaviBar: UINavigationItem!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let url = "http://www.backpack.tf/pricelist/spreadsheet"
let requestURL = NSURL(string: url)
let request = NSURLRequest(URL: requestURL!)
SpreadsheetView.loadRequest(request)
self.navigationController?.navigationBar.titleTextAttributes = [ NSFontAttributeName: UIFont(name: "TF2Build", size: 12)!]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func webViewDidStartLoad(_ : UIWebView) {
Loading.startAnimating()
NSLog("Loading")
}
func webViewDidFinishLoad(_ : UIWebView) {
Loading.stopAnimating()
NSLog("Done")
if SpreadsheetView.canGoBack {
BackButton.enabled = true
}
else {
BackButton.enabled = false
}
if SpreadsheetView.canGoForward {
ForwardButton.enabled = true
}
else {
ForwardButton.enabled = false
}
}
#IBAction func Reload(sender: AnyObject) {
SpreadsheetView.reload()
}
#IBAction func Back(sender: AnyObject) {
SpreadsheetView.goBack()
}
#IBAction func Forward(sender: AnyObject) {
SpreadsheetView.goForward()
}
}