how to gradient a background of a tableview in swift - swift3

func setTableViewBackgroundGradient(sender: UITableViewController, _ topColor:UIColor, _ bottomColor:UIColor) {
let gradientBackgroundColors = [topColor.cgColor, bottomColor.cgColor]
let gradientLocations = [0.0,1.0]
let gradientLayer = CAGradientLayer()
gradientLayer.colors = gradientBackgroundColors
gradientLayer.locations = gradientLocations as [NSNumber]
gradientLayer.frame = sender.tableView.bounds
let backgroundView = UIView(frame: sender.tableView.bounds)
backgroundView.layer.insertSublayer(gradientLayer, at: 0)
sender.tableView.backgroundView = backgroundView
}

Try this it's working for me (Swift 4)
Note : First of all set Tableview Cell & Cell ContentView Background
Color to Clear Color.
#IBOutlet fileprivate weak var tblVw: UITableView!
private var gradientLayer = CAGradientLayer()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if gradientLayer.superlayer != nil {
gradientLayer.removeFromSuperlayer()
}
let topColor = UIColor(red: 16.0/255.0, green: 12.0/255.0, blue: 54.0/255.0, alpha: 1.0)
let bottomColor = UIColor(red: 57.0/255.0, green: 33.0/255.0, blue: 61.0/255.0, alpha: 1.0)
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 1.0)
gradientLayer.colors = [topColor.cgColor, bottomColor.cgColor]
gradientLayer.frame = tblVw.bounds
let backgroundView = UIView(frame: tblVw.bounds)
backgroundView.layer.insertSublayer(gradientLayer, at: 0)
tblVw.backgroundView = backgroundView
}
Output:

Related

Read UIColor value from a function

I have a func to retrieve the RGB of an image. In the playground, the function return value as an array [r 0.0 g 0.459 b 0.761 a 1.0]
import Foundation
func findColors(_ image: UIImage) -> [UIColor] {
let pixelsWide = Int(image.size.width)
let pixelsHigh = Int(image.size.height)
guard let pixelData = image.cgImage?.dataProvider?.data else { return [] }
let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
var imageColors: [UIColor] = []
for x in 0..<1 {
for y in 0..<1 {
let point = CGPoint(x: x, y: y)
let pixelInfo: Int = ((pixelsWide * Int(point.y)) + Int(point.x)) * 4
let color = UIColor(red: CGFloat(data[pixelInfo]) / 255.0,
green: CGFloat(data[pixelInfo + 1]) / 255.0,
blue: CGFloat(data[pixelInfo + 2]) / 255.0,
alpha: CGFloat(data[pixelInfo + 3]) / 255.0)
imageColors.append(color)
}
}
return imageColors
}
I tried to display the color based on this RGB array in the ContentView but it gives me an error. Could you please advise?
import SwiftUI
let image = UIImage(named: "Fish.jpg")!
struct ContentView: View {
var body: some View {
Color(findColors(image))
.frame(width:10, height: 10)
.position(x: 40, y: 40)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
i tried to called the function in ContentView but it gives error

Errors after changing NSNumber to Int/Double

I have this class to get data from Firestore:
struct Spty: Identifiable{
var id: String
var spty: String
var r: NSNumber
var g: NSNumber
var b: NSNumber
}
class SptyViewModel: NSObject, ObservableObject{
#Published var specialities = [Spty]()
#Published var search = ""
func fetchData(){
let db = Firestore.firestore()
db.collection("specialities").addSnapshotListener { (querySnapshot, error) in
guard let documents = querySnapshot else {return }
self.specialities = documents.documents.compactMap { (doc) -> Spty? in
let id = doc.documentID
if let spty = doc.get("spty") as? String,
let r = doc.get("r") as? NSNumber,
let g = doc.get("g") as? NSNumber,
let b = doc.get("b") as? NSNumber{
return Spty(id: id, spty: spty, r: r , g: g , b: b )
}
else{
return nil
}
}
}
}
}
And I Displayed it using ForEach:
ForEach(sptyModel.specialities){ spty in
NavigationLink(destination: More()) {
HStack{
Text(spty.spty).foregroundColor(.yellow)
.frame(width: UIScreen.main.bounds.width - 30)
.frame(height: 105)
.background(Color(UIColor(red: CGFloat(truncating: spty.r) / 255.0, green: CGFloat(truncating: spty.g) / 255.0, blue: CGFloat(truncating: spty.b) / 255.0, alpha: 1.0)))
.cornerRadius(38)
.padding(.bottom, 20)
}
}
}
Because of the necessity of the usage of Codable, I need to change NSNumber to Int/Double. After simply just changing it in the class SptyViewModel, I got the following errors in ForEach
How can I solve them
Your problem is not with the ForEach , but the .background(...)
CGFloat(truncating:NSNumber) accept NSNumber only .
ForEach(sptyModel.specialities){ spty in
NavigationLink(destination: Text("MORE")) {
HStack{
Text(spty.spty).foregroundColor(.yellow)
.frame(width: UIScreen.main.bounds.width - 30)
.frame(height: 105)
.background(Color(UIColor(red: CGFloat(truncating: NSNumber(value: spty.r)) / 255.0, green: CGFloat(truncating: NSNumber(value: spty.g)) / 255.0, blue: CGFloat(truncating: NSNumber(value: spty.b)) / 255.0, alpha: 1.0)))
.cornerRadius(38)
.padding(.bottom, 20)
}
}
}
Firebase stores a NSNumber, but you can simply cast it as a Double or Int. Instead of casting "as? NSNumber", just change NSNumber to Int or Double. You'll need to update Spty struct variable types as well.

How to move scrollview with buttons only in SwiftUI

Previously I did with Swift4 UIScrollView which scrolled with buttons and x offset.
In Swift4 I have:
Set Scrolling Enabled and Paging Enabled to false.
Created the margins, offsets for each frame in UIScrollView and changed the position with buttons Back and Next.
Here is the code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var buttonSound: UIButton!
#IBOutlet weak var buttonPrev: UIButton!
#IBOutlet weak var buttonNext: UIButton!
#IBOutlet weak var scrollView: UIScrollView!
var levels = ["level1", "level2", "level3", "level4"]
let screenWidth = UIScreen.main.bounds.width
let screenHeight = UIScreen.main.bounds.height
var currentLevel = 1
var previousLevel: Int? = nil
override func viewDidLoad() {
super.viewDidLoad()
//Defining the Various Swipe directions (left, right, up, down)
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(self.handleGesture(gesture:)))
swipeLeft.direction = .left
self.view.addGestureRecognizer(swipeLeft)
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(self.handleGesture(gesture:)))
swipeRight.direction = .right
self.view.addGestureRecognizer(swipeRight)
addHorizontalLevelsList()
customizeButtons()
resizeSelected()
}
func addHorizontalLevelsList() {
var frame : CGRect?
for i in 0..<levels.count {
let button = UIButton(type: .custom)
let buttonW = screenWidth/3
let buttonH = screenHeight/2
frame = CGRect(x: CGFloat(i+1) * (screenWidth/2) - (buttonW/2),
y: buttonH - 100,
width: buttonW,
height: buttonH)
button.frame = frame!
button.tag = i+1
button.backgroundColor = .lightGray
button.addTarget(self, action: #selector(selectTeam), for: .touchUpInside)
button.setTitle(levels[i], for: .normal)
scrollView.addSubview(button)
}
scrollView.contentSize = CGSize(width: (screenWidth/2 * CGFloat(levels.count)),
height: screenHeight)
scrollView.backgroundColor = .clear
self.view.addSubview(scrollView)
}
func customizeButtons(){
buttonPrev.frame = CGRect(x: 0,
y: (screenHeight/2) - 40,
width: 80, height: 80)
buttonNext.frame = CGRect(x: screenWidth - 80,
y: (screenHeight/2) - 40,
width: 80, height: 80)
buttonPrev.superview?.bringSubviewToFront(buttonPrev)
buttonNext.superview?.bringSubviewToFront(buttonNext)
}
#objc func selectTeam(button: UIButton) {
button.transform = CGAffineTransform(scaleX: 0.6, y: 0.6)
UIView.animate(withDuration: 1.0,
delay: 0,
usingSpringWithDamping: CGFloat(0.20),
initialSpringVelocity: CGFloat(6.0),
options: UIView.AnimationOptions.allowUserInteraction,
animations: {
button.transform = CGAffineTransform.identity
},
completion: { Void in() }
)
print(levels[button.tag])
let vc = PopTypeVC(nibName: "PopTypeVC", bundle: nil)
vc.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
self.present(vc, animated: true)
}
#IBAction func prevLevel(_ sender: Any) {
if currentLevel > 0 {
currentLevel -= 1
scroll()
}
}
#IBAction func nextLevel(_ sender: Any) {
if currentLevel < levels.count {
currentLevel += 1
scroll()
}
}
func scroll(){
print(currentLevel)
print(previousLevel as Any)
scrollView.setContentOffset(CGPoint(x: currentLevel * Int(screenWidth/2), y: 0), animated: true)
resizeSelected()
}
// The #objc before func is a must, since we are using #selector (above)
#objc func handleGesture(gesture: UISwipeGestureRecognizer) -> Void {
if gesture.direction == UISwipeGestureRecognizer.Direction.right {
prevLevel(self)
}
else if gesture.direction == UISwipeGestureRecognizer.Direction.left {
nextLevel(self)
}
}
func resizeSelected(){
if previousLevel != nil {
let previousFrame = CGRect(x:CGFloat(previousLevel!) * (screenWidth/2) - (screenWidth/3)/2,
y: (screenHeight/2) - 100,
width: screenWidth/3,
height: screenHeight/2)
scrollView.viewWithTag(previousLevel!)?.frame = previousFrame
}
let currentFrame = CGRect(x: CGFloat(currentLevel) * (screenWidth/2) - (screenWidth/3)/2 - 10,
y: (screenHeight/2) - 110,
width: screenWidth/3 + 20,
height: screenHeight/2 + 20)
scrollView.viewWithTag(currentLevel)?.frame = currentFrame
previousLevel = currentLevel
}
}
The problem is I can't do this with SwiftUI:
struct ContentView: View {
static var levels = ["level1",
"level2",
"level3",
"level4"]
var currentLevel = 1
var previousLevel: Int? = nil
let screenW = UIScreen.main.bounds.width
let screenH = UIScreen.main.bounds.height
let margin1 = 50
let margin2 = 100
let margin3 = 20
let sceneButtonW = 100
let buttonPadding = 40
var body: some View {
ZStack {
// Horizontal list
VStack {
Spacer()
.frame(height: margin2)
ScrollView(.horizontal, showsIndicators: false) {
HStack{
Spacer()
.frame(width: buttonPadding + sceneButtonW/2)
ForEach(0..<ContentView.levels.count) { i in
cardView(i: i).tag(i+1)
}
Spacer()
.frame(width: buttonPadding + sceneButtonW/2)
}
}
Spacer()
.frame(height: margin3)
}
}
.background(Image("bg")
.resizable()
.edgesIgnoringSafeArea(.all)
.aspectRatio(contentMode: .fill))
}
}
Question: Are there any methods to disable automatic scrolling at all and use offsets at ScrollView with SwiftUI?
This already built solution for SwiftUI
https://github.com/fermoya/SwiftUIPager
However, there is no real example.

How to set Gradient color for statusbar

Code:
extension UIApplication {
class var statusBarBackgroundColor: UIColor? {
get {
return (shared.value(forKey: "statusBar") as? UIView)?.backgroundColor
} set {
(shared.value(forKey: "statusBar") as? UIView)?.backgroundColor = newValue
}
}
}
UIApplication.statusBarBackgroundColor = .blue
I am trying to set gradient colour for status bar alone.How to change my code to set gradient colour.any help will be appreciated.thanks in advance
This is how I manage it.
let gradientLayer = CAGradientLayer()
gradientLayer.frame = CGRect(x:0, y:-20, width:375, height:64)
let colorTop = UIColor(red: 69/255, green: 90/255, blue: 195/255, alpha: 1.0).cgColor
let colorBottom = UIColor(red: 230/255, green: 44/255, blue: 75/255, alpha: 1.0).cgColor
gradientLayer.colors = [ colorTop, colorBottom]
gradientLayer.locations = [ 0.0, 1.0]
gradientLayer.frame = CGRect(x:0, y:-20, width:375, height:self.view.frame.height * 0.06)
let window: UIWindow? = UIApplication.shared.keyWindow
let view = UIView()
view.backgroundColor = UIColor.clear
view.translatesAutoresizingMaskIntoConstraints = false
view.frame = CGRect(x: 0, y: 0, width: (window?.frame.width)!, height: self.view.frame.height * 0.07)
view.layer.addSublayer(gradientLayer)
window?.addSubview(view)
That only add the gradient to the view behind the status bar

Image Slider with UIScrollView

I am making an image slider that slides automatically every 2 seconds. The code I have wrote moves immediately to the next image without the slide animation, I want to fix it somehow by showing the scrollview scrolling, this is my code:
var imagesArray = [UIImage]()
static var i = 0
override func viewDidLoad() {
super.viewDidLoad()
imagesArray = [image1, image2, image3, image4]
for i in 0..<imagesArray.count{
let imageview = UIImageView()
imageview.image = imagesArray[i]
imageview.contentMode = .scaleAspectFit
let xPosition = self.view.frame.width * CGFloat(i)
imageview.frame = CGRect(x: xPosition, y: 0, width: self.imagesScrollView.frame.width, height: self.imagesScrollView.frame.height)
imagesScrollView.contentSize.width = imagesScrollView.frame.width * CGFloat(i+1)
imagesScrollView.addSubview(imageview)
}
}
override func viewDidAppear(_ animated: Bool) {
let scrollingTimer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(MenuViewController.newStartScrolling), userInfo: nil, repeats: true)
scrollingTimer.fire()
func newStartScrolling()
{
if MenuViewController.i == imagesArray.count {
MenuViewController.i = 0
}
let x = CGFloat(MenuViewController.i) * imagesScrollView.frame.size.width
imagesScrollView.contentOffset = CGPoint(x: x, y: 0)
MenuViewController.i += 1
}
Thank you.
Please try this code.
override func viewDidAppear(_ animated: Bool) {
imagesArray = [UIImage(named: "apple.jpg")!, UIImage(named: "empire.jpg")!, UIImage(named: "ottawa.jpg")!]
imagesScrollView.contentSize = CGSize(width: imagesScrollView.frame.width * CGFloat(imagesArray.count), height: imagesScrollView.frame.height)
for i in 0..<imagesArray.count{
let imageview = UIImageView()
imageview.image = imagesArray[i]
imageview.contentMode = .scaleAspectFill
imageview.clipsToBounds = true
let xPosition = self.imagesScrollView.frame.width * CGFloat(i)
imageview.frame = CGRect(x: xPosition, y: 0, width: self.imagesScrollView.frame.width, height: self.imagesScrollView.frame.height)
print(imageview)
imagesScrollView.addSubview(imageview)
}
let scrollingTimer = Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(ViewController.newStartScrolling), userInfo: nil, repeats: true)
scrollingTimer.fire()
}
func newStartScrolling()
{
if ViewController.i == imagesArray.count {
ViewController.i = 0
}
let x = CGFloat(ViewController.i) * imagesScrollView.frame.size.width
imagesScrollView.setContentOffset(CGPoint(x: x, y: 0), animated: true)
ViewController.i += 1
}
you have to use func setContentOffset(_ contentOffset: CGPoint, animated: Bool) method to change content offset using animation.
#IBOutlet weak var imageView:UIImageView!
var i=Int()
override func viewDidLoad() {
super.viewDidLoad()
Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(imageChange), userInfo: nil, repeats: true)
// Do any additional setup after loading the view.
}
#objc func imageChange(){
self.imageView.image=images[i]
if i<images.count-1{
i+=1
}
else{
i=0
}
}