I'm trying to add add SwiftUI Path to a Scenekit Scene (as SCNShape).
I created:
Scenekit View (image 1)
SwiftUI Path (image 2)
Then I tried to call the SwiftUI Path, based on the approach bellow:
Unable to create circle using UIBezierPath and SCNShape
let scnpath = ContentView()
let shape = SCNShape(path: scnpath)
let shapeNode = SCNNode(geometry: shape)
Didn't work, as results bellow:
import SwiftUI
import SceneKit
struct ScenekitView : UIViewRepresentable {
let scene = SCNScene(named: "art.scnassets/ship.scn")!
func makeUIView(context: Context) -> SCNView {
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
// add SwiftUI Path to Scenekit Scene
let scnpath = ContentView()
let shape = SCNShape(path: scnpath)
let shapeNode = SCNNode(geometry: shape)
// place the camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
// retrieve the SCNView
let scnView = SCNView()
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
scnView.scene = scene
}
}
#if DEBUG
struct ScenekitView_Previews : PreviewProvider {
static var previews: some View {
ScenekitView()
.colorScheme(.dark)
.previewDevice("iPad Pro (12.9-inch) (3rd generation)")
}
}
#endif
import SwiftUI
struct ContentView: View {
var body: some View {
Path { path in
path.move(to: CGPoint(x: 63.5, y: 98.38))
path.addLine(to: CGPoint(x: 920.14, y: 0))
path.addLine(to: CGPoint(x: 1094.24, y: 584.81))
path.addLine(to: CGPoint(x: 920.14, y: 938.58))
path.addLine(to: CGPoint(x: 498.47, y: 1279.73))
path.addLine(to: CGPoint(x: 211.79, y: 938.58))
path.addLine(to: CGPoint(x: 617.65, y: 584.81))
path.addLine(to: CGPoint(x: 735.35, y: 295.94))
path.addLine(to: CGPoint(x: 332.02, y: 349.08))
path.addLine(to: CGPoint(x: 0, y: 672.25))
path.addLine(to: CGPoint(x: 63.5, y: 98.38))
}
.stroke(Color.blue, lineWidth: 3)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Really appreciate any help!
Cheers
Your SwiftUI ContentView is a View, which is struct, but SCNShape expected UIBezierPath which is a class. So if you want to join those different concepts, you have to do something like the following:
In ContentView
struct ContentView: View {
let path = Path { path in
path.move(to: CGPoint(x: 63.5, y: 98.38))
path.addLine(to: CGPoint(x: 920.14, y: 0))
path.addLine(to: CGPoint(x: 1094.24, y: 584.81))
path.addLine(to: CGPoint(x: 920.14, y: 938.58))
path.addLine(to: CGPoint(x: 498.47, y: 1279.73))
path.addLine(to: CGPoint(x: 211.79, y: 938.58))
path.addLine(to: CGPoint(x: 617.65, y: 584.81))
path.addLine(to: CGPoint(x: 735.35, y: 295.94))
path.addLine(to: CGPoint(x: 332.02, y: 349.08))
path.addLine(to: CGPoint(x: 0, y: 672.25))
path.addLine(to: CGPoint(x: 63.5, y: 98.38))
}
var body: some View {
self.path
.stroke(Color.blue, lineWidth: 3)
}
}
In ScenekitView
let scnpath = ContentView().path.cgPath
let shape = SCNShape(path: UIBezierPath(cgPath: scnpath), extrusionDepth: 1.0)
try this:
1) you did not add your shapenode to the scene - so you won't see it
2) in the beginning, if you are not so well experienced with scenekit, you should not control the camera yourself...let this scenekit do for you, so i deleted your camera (because it needs the right position + angle so that you can really see something
3.) update the shape to your shape like asperi told you - this is one way you can go (i did not put this in my running example, because it would be too easy for you ;))
4.) result is as it is shown in picture
5.) i don't know whether you know: in the simulator you can only see scenekitviews if you tap the "play" button in the simulator...
struct ScenekitView : UIViewRepresentable {
let scene = SCNScene()
func makeUIView(context: Context) -> SCNView {
let uiView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
// scene.rootNode.addChildNode(cameraNode)
// add SwiftUI Path to Scenekit Scene
let bezierPath = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 20, height: 20))
let shape = SCNShape(path: bezierPath, extrusionDepth: 50)
let shapeNode = SCNNode(geometry: shape)
// place the camera
cameraNode.position = SCNVector3(x: 0, y: 10, z: 25)
// scene.rootNode.addChildNode(cameraNode)
scene.rootNode.addChildNode(shapeNode)
// retrieve the SCNView
let scnView = SCNView()
scnView.scene = scene
scnView.backgroundColor = UIColor.blue
scnView.frame = CGRect(x: 0, y: 0, width: 500, height: 500)
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
print("test")
}
}
if you want to make it a bittle bit "sexier" you can add specular and a light...and you get:
code here:
struct ScenekitView : UIViewRepresentable {
let scene = SCNScene()
func makeUIView(context: Context) -> SCNView {
let uiView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
let bezierPath = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 20, height: 20))
let shape = SCNShape(path: bezierPath, extrusionDepth: 40)
let shapeNode = SCNNode(geometry: shape)
let material = SCNMaterial()
material.diffuse.contents = UIColor.red
material.specular.contents = UIColor.white
let light = SCNLight()
light.type = .spot
cameraNode.light = light
shape.materials = [material]
shapeNode.rotation = SCNVector4(0.2, 0.3, 0.1, CGFloat.pi / 2)
// place the camera
cameraNode.position = SCNVector3(x: 5, y: 16, z: 85)
scene.rootNode.addChildNode(cameraNode)
scene.rootNode.addChildNode(shapeNode)
// retrieve the SCNView
let scnView = SCNView()
scnView.scene = scene
scnView.backgroundColor = UIColor.blue
scnView.frame = CGRect(x: 0, y: 0, width: 400, height: 400)
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
print("test")
}
}
Related
enter image description here> I make the word game, the problem is this. When the word is big, the
cells come out of the screen, I need these cells to move below the
other cells and be centered. and the cells should have a fixed width =
20. that's all in my application Help implement.
p.s. I tried to add elements to the stackview, but the space between the words did not appear in the stackview
1. TileView.swift
import UIKit
protocol TileDragDelegateProtocol {
func tileView(tileView: TileView, didDragToPoint: CGPoint)
}
class TileView: UIImageView {
var letter: Character?
var isMatch = false
private var xOffset: CGFloat = 0.0
private var yOffset: CGFloat = 0.0
var dragDelegate: TileDragDelegateProtocol?
init(letter: Character, sideLength: CGFloat) {
self.letter = letter
//let scale = CGRect(x: 0, y: 0, width: self.bounds.size.width /* scale*/, height: self.bounds.size.height /** scale*/)
// super.init(frame: scale)
// let scale = CGRect(x: 0, y: 0, width: self.bounds.size.width /* scale*/, height: self.bounds.size.height /** scale*/)
let image = UIImage(named: "tile")
super.init(image: image)
let scale = sideLength / (image?.size.width)!
self.frame = CGRect(x: 0, y: 0, width: (image?.size.width)! * scale, height: (image?.size.height)! * scale)
// self.frame = CGRect(x: 0, y: 0, width: self.bounds.size.width /* scale*/, height: self.bounds.size.height /** scale*/)
//self.layer.cornerRadius = 23
//self.clipsToBounds = true
let letterLabel = UILabel(frame: self.bounds)
letterLabel.textAlignment = .center
letterLabel.textColor = .white
letterLabel.backgroundColor = .clear
letterLabel.text = String(letter).uppercased()
letterLabel.font = .boldSystemFont(ofSize: 40.0 / 3) //.systemFont(ofSize: 78.0 / 3/*scale*/)
//letterLabel.layer.cornerRadius = 23
//letterLabel.clipsToBounds = true
// self.backgroundColor = .red
// self.textAlignment = .center
// self.textColor = .white
// self.backgroundColor = .black
// self.text = String(letter).uppercased()
// self.font = .boldSystemFont(ofSize: 50.0 / 3)
self.addSubview(letterLabel)
self.isUserInteractionEnabled = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let point = touch.location(in: self.superview)
xOffset = point.x - self.center.x
yOffset = point.y - self.center.y
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let point = touch.location(in: self.superview)
self.center = CGPoint(x: point.x - xOffset, y: point.y - yOffset)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.touchesMoved(touches, with: event)
dragDelegate?.tileView(tileView: self, didDragToPoint: self.center)
}
}
2.TargetView.swift
import UIKit
class TargetView: UILabel {
var letter: Character!
var isMatch = false
init(letter: Character, sideLength: CGFloat) {
self.letter = letter
//let image = UIImage(named: "slot")
//super.init(image: image)
//let scale = CGRect(x: 0, y: 0, width: (image?.size.width)! * scale, height: (image?.size.height)! * scale)
super.init(frame: CGRect(x: 0, y: 0, width: 15, height: 30))
self.backgroundColor = .red
self.textAlignment = .center
self.font = .boldSystemFont(ofSize: 60.0 / 3)
self.text = "_"//String(letter).uppercased()
self.textColor = .white
self.lineBreakMode = .byWordWrapping
self.adjustsFontSizeToFitWidth = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
3. ViewController
import UIKit
class ViewController: UIViewController {
// let ScreenWidth = UIScreen.main.bounds.size.width
// let ScreenHeight = UIScreen.main.bounds.size.height
//frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
//var gameView = UIView()
private var tiles = [TileView]()
private var targets = [TargetView]()
let tileMargin : CGFloat = 0.0
var words = "Hellomyf rie nds?"
// lazy var stackView: UIStackView = {
// let stack = UIStackView()
// stack.axis = .horizontal
// stack.spacing = 0
// stack.distribution = .fillEqually
// stack.translatesAutoresizingMaskIntoConstraints = false
// return stack
// }()
//
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .lightGray
dealRandomAnagram()
}
func dealRandomAnagram() {
let anagram1 = words
let anagram1length = anagram1.count
print("phrase1[\(anagram1length)]: \(anagram1)")
// Рассчет размера плитки //Tile size calculation
let tileSize = ceil(UIScreen.main.bounds.size.width * 0.8 / CGFloat(min(anagram1length, anagram1length))) + tileMargin // * 1
//Поиск х позиции первой плитки // Finding x position of the first tile
var xOffset = (UIScreen.main.bounds.size.width - CGFloat(max(anagram1length, anagram1length)) * (15 + tileMargin)) / 2.0
//+ tileMargin
//let yOffset = (UIScreen.main.bounds.size.height - CGFloat(max(anagram1length, anagram1length)) * (15 + tileMargin)) / 2.0
//+ tileMargin
//настройка центра плитки (вместо источника плитки)
xOffset += tileSize / 2.0
tiles = []
// создание плитки
for (index, letter) in anagram1.enumerated() {
if letter != " " {
let tile = TileView(letter: letter, sideLength: tileSize)
tile.center = CGPoint(x: xOffset + CGFloat(index) * (tileSize + tileMargin), y: UIScreen.main.bounds.size.height/4*3)
view.addSubview(tile)
tile.dragDelegate = self
tiles.append(tile)
}
}
targets = []
for (index,letter) in anagram1.enumerated() {
let target = TargetView(letter: letter, sideLength: 15)
if letter != " " || index > 15 {
// let target = TargetView(letter: letter, sideLength: 15)
target.center = CGPoint(x: xOffset + CGFloat(index) /* * 20 */ * (15 + tileMargin), y: UIScreen.main.bounds.size.height - 100) //100 //UIScreen.main.bounds.size.height - CGFloat(index) * 50
view.addSubview(target)
targets.append(target)
//stackView.addArrangedSubview(target)
//targets.append(target)
}
}
}
//xOffset + CGFloat(index) /* * 20 */ * (tileSize + tileMargin )
//UIScreen.main.bounds.size.height - 100
func placeTile(tileView: TileView, targetView: TargetView) {
tileView.isMatch = true
targetView.isMatch = true
tileView.isUserInteractionEnabled = false
UIView.animate(withDuration: 0.35, delay: 0.0, options: UIView.AnimationOptions.curveEaseOut, animations: {
tileView.center = targetView.center
tileView.backgroundColor = .clear
targetView.transform = .identity
}, completion: {
(value: Bool) in
targetView.isHidden = true
})
}
func checkValidate() {
for targetView in targets {
if !targetView.isMatch {
return
}
}
print("Valid")
}
}
extension ViewController: TileDragDelegateProtocol {
func tileView(tileView: TileView, didDragToPoint: CGPoint) {
var targetView: TargetView?
for tv in targets {
if tv.frame.contains(didDragToPoint) && !tv.isMatch {
targetView = tv
break
}
}
if let targetView = targetView {
//2 check if letter matches
if targetView.letter == tileView.letter {
//3
self.placeTile(tileView: tileView, targetView: targetView)
print("Success! You should place the tile here!")
//more stuff to do on success here
self.checkValidate()
print("Check if the player has completed the phrase")
} else {
//4
UIView.animate(withDuration:0.35,
delay:0.00,
options :UIView.AnimationOptions.curveEaseOut,
animations: {
tileView.center = CGPoint(x: tileView.center.x,
y: tileView.center.y - (200))
},
completion: nil)
print("Failure. Let the player know this tile doesn't belong here")
//more stuff to do on failure here
}
}
}
}
My swift code uses a button to place imageviews on a uiviewcontroller that parent from a empty array. The problem is I dont know how to effect the size of the invidicual imageview after it is placed on the uiview controller. When a imageview is click and then when the slider is moved the imageview should change size. However what is happening is the value when the slider is changed effects the next iamgeview that is placed on the uiviewcontroller. Pitcure below is included I circled what the slider should effect. This is a video of what I am trying to do https://www.youtube.com/watch?v=ho6ID6XVEYw&feature=youtu.be.
import UIKit
class ViewController: UIViewController {
var sx = UISlider()
var count: Int = 0
var ht = -90
var ww = 80
var arrTextFields = [UIImageView]()
var b7 = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
[b7,sx].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
$0.backgroundColor = .systemOrange
}
b7.frame = CGRect(x: view.center.x-115, y: view.center.y + 200, width: 70, height: 40)
sx.frame = CGRect(x: view.center.x-115, y: view.center.y-200, width: 70, height: 40)
b7.addTarget(self, action: #selector(addBOx), for: .touchUpInside)
}
//func that adds imageview.
#objc func addBOx() {
let subview = UIImageView()
subview.isUserInteractionEnabled = true
arrTextFields.append(subview)
view.addSubview(subview)
sx.addTarget(self, action: #selector(ji), for: .valueChanged)
sx.minimumValue = 10
sx.maximumValue = 150
subview.frame = CGRect(x: view.bounds.midX - 0, y: view.bounds.midY + CGFloat(ht), width: CGFloat(ww), height: 35)
subview.backgroundColor = .purple
subview.tag = count
let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePanGestured(_:)))
subview.addGestureRecognizer(pan)
count += 1
ht += 50
arrTextFields.append(subview)
}
#objc func handlePanGestured(_ gesture: UIPanGestureRecognizer) {
let draggedView = gesture.view!
view.bringSubviewToFront(draggedView)
let translation = gesture.translation(in: view)
draggedView.center = CGPoint(x: draggedView.center.x + translation.x, y: draggedView.center.y + translation.y)
gesture.setTranslation(.zero, in: view)
}
#objc func ji(sender : UISlider){
ww = Int(sx.value)
}}
The main idea that needs to be implemented is to add the currentView variable to find out which view we want to change.
We also need to add some functionality to select the specific view that needs to be changed.
1) Add variable currentView
class ViewController: UIViewController {
...
var currentView: UIView?
override func viewDidLoad() {
super.viewDidLoad()
2) Add tapGestureRecognozer to func addBOx()
#objc func addBOx() {
...
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGestured(_:)))
subview.addGestureRecognizer(tapGesture)
}
3) Add handleTapGestured(_:)
#objc func handleTapGestured(_ gesture: UIPanGestureRecognizer) {
currentView = gesture.view
}
4) Update func ji(sender: UISlider)
#objc func ji(sender: UISlider) {
...
currentView?.bounds.size.width = CGFloat(sx.value)
}
All code:
import UIKit
class ViewController: UIViewController {
var sx = UISlider()
var count: Int = 0
var ht = -90
var ww = 80
var arrTextFields = [UIImageView]()
var b7 = UIButton()
var currentView: UIView?
override func viewDidLoad() {
super.viewDidLoad()
[b7,sx].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
$0.backgroundColor = .systemOrange
}
b7.frame = CGRect(x: view.center.x-115, y: view.center.y + 200, width: 70, height: 40)
sx.frame = CGRect(x: view.center.x-115, y: view.center.y-200, width: 70, height: 40)
b7.addTarget(self, action: #selector(addBOx), for: .touchUpInside)
}
//func that adds imageview.
#objc func addBOx() {
let subview = UIImageView()
subview.isUserInteractionEnabled = true
arrTextFields.append(subview)
view.addSubview(subview)
sx.addTarget(self, action: #selector(ji), for: .valueChanged)
sx.minimumValue = 10
sx.maximumValue = 150
subview.frame = CGRect(x: view.bounds.midX - 0, y: view.bounds.midY + CGFloat(ht), width: CGFloat(ww), height: 35)
subview.backgroundColor = .purple
subview.tag = count
let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePanGestured(_:)))
subview.addGestureRecognizer(pan)
count += 1
ht += 50
arrTextFields.append(subview)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGestured(_:)))
subview.addGestureRecognizer(tapGesture)
}
#objc func handleTapGestured(_ gesture: UIPanGestureRecognizer) {
currentView = gesture.view
}
#objc func handlePanGestured(_ gesture: UIPanGestureRecognizer) {
let draggedView = gesture.view!
view.bringSubviewToFront(draggedView)
let translation = gesture.translation(in: view)
draggedView.center = CGPoint(x: draggedView.center.x + translation.x, y: draggedView.center.y + translation.y)
gesture.setTranslation(.zero, in: view)
}
#objc func ji(sender : UISlider){
ww = Int(sx.value)
currentView?.bounds.size.width = CGFloat(sx.value)
}
}
Alternatively, you can add a textField and write the number that the element from your array needs to change.
And please, don't use variables like sx, ht, ww, b7 in your code.
You can read API Design Guidelines here
I have SCNCylinder in a SCNScene and a button in a SwiftUI frame below it. Whenever the button is pressed the cylinder is expected to rotate by 90°. I am not getting the expected result with my code.
//SwiftUI
struct ContentView: View {
var body: some View {
VStack{
Button(action: {
// What to perform
let rotationangle = 180.0
}) {
// How the button looks like
Text("90°")
.frame(width: 100, height: 100)
.position(x: 225, y: 500)
}
SceneKitView()
.frame(width: 300, height: 300)
.position(x: 0, y: 200)
}
}
}
//SceneKit
struct SceneKitView: UIViewRepresentable {
func makeUIView(context:
UIViewRepresentableContext<SceneKitView>) -> SCNView {
//Scene properties
let sceneView = SCNView()
sceneView.scene = SCNScene()
sceneView.allowsCameraControl = true
sceneView.autoenablesDefaultLighting = true
sceneView.backgroundColor = UIColor.white
sceneView.frame = CGRect(x: 0, y: 10, width: 0, height: 1)
//Cylinder properties
let cylinder = SCNCylinder(radius: 0.02, height: 2.0)
let cylindernode = SCNNode(geometry: cylinder)
cylindernode.position = SCNVector3(x: 0, y: 0, z: 0)
cylinder.firstMaterial?.diffuse.contents = UIColor.green
//Pivot and rotation of the cylinder
func degreesToRadians(_ degrees: Float) -> CGFloat {
return CGFloat(degrees * .pi / 180)
}
cylindernode.pivot = SCNMatrix4MakeTranslation(0, -1, 0)
//Line with an error: Use of unresolved identifier ‘rotationangle’
let rotation = SCNAction.rotate(by: degreesToRadians(rotationangle), around: SCNVector3 (1, 0, 0), duration: 5)
sceneView.scene?.rootNode.addChildNode(cylindernode)
cylindernode.runAction(rotation)
return sceneView
}
func updateUIView(_ uiView: SCNView, context: UIViewRepresentableContext<SceneKitView>) {
}
typealias UIViewType = SCNView
}
I am having a error saying “ Use of unresolved identifier ‘rotationangle’ “ during using ‘rotationangle‘ in SCNAction.
You need to declare a #State in your ContentView and set the value of the property in your Button action.
You then need to declare an angle property in your SceneKitView as a #Binding and use that value for it to work properly.
I haven't yet tested this out. Keep in mind that you don't have cone declared anywhere so I'm not sure what that is.
import SwiftUI
import SceneKit
struct ContentView: View {
#State var rotationAngle: Float = 0.0
var body: some View {
VStack {
Button(action: {
// What to perform
self.rotationAngle = 180.0
}) {
// How the button looks like
Text("90°")
.frame(width: 100, height: 100)
.position(x: 225, y: 500)
}
SceneKitView(angle: self.$rotationAngle)
.frame(width: 300, height: 300)
.position(x: 0, y: 200)
}
}
}
//SceneKit
struct SceneKitView: UIViewRepresentable {
#Binding var angle: Float
func degreesToRadians(_ degrees: Float) -> CGFloat {
print(degrees)
return CGFloat(degrees * .pi / 180)
}
func makeUIView(context: UIViewRepresentableContext<SceneKitView>) -> SCNView {
// Scene properties
let sceneView = SCNView()
sceneView.scene = SCNScene()
sceneView.allowsCameraControl = true
sceneView.autoenablesDefaultLighting = true
sceneView.backgroundColor = UIColor.white
sceneView.frame = CGRect(x: 0, y: 10, width: 0, height: 1)
return sceneView
}
func updateUIView (_ sceneView: SCNView, context: UIViewRepresentableContext<SceneKitView>) {
if self.angle > 0 {
// Cylinder properties
let cylinder = SCNCylinder(radius: 0.02, height: 2.0)
let cylindernode = SCNNode(geometry: cylinder)
cylindernode.position = SCNVector3(x: 0, y: 0, z: 0)
// cone.firstMaterial?.diffuse.contents = UIColor.green
// Pivot and rotation of the cylinder
cylindernode.pivot = SCNMatrix4MakeTranslation(0, -1, 0)
sceneView.scene?.rootNode.addChildNode(cylindernode)
//Line with an error: Use of unresolved identifier ‘rotationangle’
let rotation = SCNAction.rotate(by: self.degreesToRadians(self.angle), around: SCNVector3 (1, 0, 0), duration: 5)
cylindernode.runAction(rotation)
}
}
}
My swift code right now uses func addbox to append imageviews to a empty array of imageviews.
When the user taps button widthActivatorBtn it should allow the user to select on a imageview and change the width of the imageveiew. It works but only if the widthActivatorBtn was selected and selectNum is changed to 3.
I can affect imageview placed on after selectNum was changed to 3 but not the imageviews before it. Check out my gif and you can see the problem. When selectNum is changed to 3 all imageviews should be able to have their width changed via slider.
import UIKit
class ViewController: UIViewController {
var slider = UISlider()
var ht = -90
var widthSize = 80
var emptyArray = [UIImageView]()
var addImageview = UIButton()
var width = UIButton()
var currentView: UIView?
var selectNum = Int()
override func viewDidLoad() {
super.viewDidLoad()
[addImageview,slider,width].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
$0.backgroundColor = .systemOrange
}
addImageview.setTitle("add imageview", for: .normal)
width.setTitle("change width", for: .normal)
addImageview.frame = CGRect(x: view.center.x-115, y: view.center.y + 200, width: 160, height: 40)
slider.frame = CGRect(x: view.center.x-115, y: view.center.y-200, width: 160, height: 40)
width.frame = CGRect(x: view.center.x-115, y: view.center.y + 100, width: 160, height: 40)
addImageview.addTarget(self, action: #selector(addBOx), for: .touchUpInside)
width.addTarget(self, action: #selector(widthActivatorBtn), for: .touchUpInside)
slider.addTarget(self, action: #selector(ji), for: .valueChanged)
slider.minimumValue = 10
slider.maximumValue = 150
}
#objc func widthActivatorBtn() {
width.backgroundColor = .systemPink
selectNum = 3
}
#objc func addBOx() {
let subview = UIImageView()
subview.isUserInteractionEnabled = true
emptyArray.append(subview)
view.addSubview(subview)
subview.frame = CGRect(x: view.bounds.midX - 0, y: view.bounds.midY + CGFloat(ht), width: CGFloat(widthSize), height: 35)
subview.backgroundColor = .purple
ht += 50
emptyArray.append(subview)
if selectNum == 3{
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGestured(_:)))
subview.addGestureRecognizer(tapGesture)
}
}
#objc func handleTapGestured(_ gesture: UIPanGestureRecognizer) {
currentView = gesture.view
}
#objc func ji(sender : UISlider){
widthSize = Int(slider.value)
currentView?.bounds.size.width = CGFloat(slider.value)
}
}
remove selectNum variable, it is causing the problem.
when you are creating the first image at that time selectNum is not equal to 3, so that the gesture is not added to the first imageView, but after cliking on width button selectNum set to value 3 and after that when you create any imageview then that imageView gets the gesture and you width logic works.
#objc func addBOx() {
let subview = UIImageView()
subview.isUserInteractionEnabled = true
emptyArray.append(subview)
view.addSubview(subview)
subview.frame = CGRect(x: view.bounds.midX - 0, y: view.bounds.midY + CGFloat(ht), width: CGFloat(widthSize), height: 35)
subview.backgroundColor = .purple
ht += 50
emptyArray.append(subview)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGestured(_:)))
subview.addGestureRecognizer(tapGesture)
}
#objc func widthActivatorBtn() {
width.backgroundColor = .systemPink
selectNum = 3
}
#objc func ji(sender : UISlider){
if selectNum == 3 {
widthSize = Int(slider.value)
currentView?.bounds.size.width = CGFloat(slider.value)
}
}
add the condition selectNum == 3 in ji func, to resize. and you can reset selectNum somewhere to stop resizing.
so now when widthActivatorBtn will be pressed then only width will change.
hope this will work for you.
I found this ready code that prints out an already stored array called (let dataArr = ["25","51","57","73","68"]) in rows into a label.
I have now made a text field that can insert to another array(my array = String) I want this array to be swaped with the first array.
But know when I swap to empty array that has already been populated via a text field it doesn’t appear in label.
I was hoping to swap the dataArr to an empty array called array that files up with data when inserted via the text field but for reason when I am doing that it doesn’t get shown in the label I am posting now to see what I am doing wrong.
But when I print the array it appears in the console but not in the label.
let dataArr = ["2,5","5,1","5,7"]
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
var yPos = 90
for i in 0..<dataArr.count {
let element = dataArr[i]
let labelNum = UILabel()
let num1Nnum2 = "number 1 : \(element)"
labelNum.text = num1Nnum2
labelNum.textAlignment = .center
labelNum.frame = CGRect( x:10, y:yPos, width:250, height: 80)
yPos += 80
self.view.addSubview(labelNum)
}
}
var array = [String]()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
var yPos = 90
for i in 0..<array.count {
let element = array[i]
let labelNum = UILabel()
let num1Nnum2 = "number 1 : \(element)"
labelNum.text = num1Nnum2
labelNum.textAlignment = .center
labelNum.frame = CGRect( x:10, y:yPos, width:250, height: 80)
yPos += 80
self.view.addSubview(labelNum)
}
}
Ran your code and got the following result.
Is this what you were expecting?
UPDATE :
Here's what whipped up.
lazy var myText: UITextField = {
let input = UITextField(frame: CGRect(x: 0, y: 0, width: 300, height: 40))
input.backgroundColor = .white
input.placeholder = "Enter data here!"
return input
}()
lazy var enterButton: UIButton = {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
button.backgroundColor = .gray
button.setTitle("ENTER", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 11)
button.addTarget(self, action: #selector(btnEnter), for: .touchUpInside)
return button
}()
lazy var doneButton: UIButton = {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
button.backgroundColor = .gray
button.setTitle("Done", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 11)
button.addTarget(self, action: #selector(btnDone), for: .touchUpInside)
return button
}()
var array = [String]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if (!array.isEmpty) {
view.backgroundColor = .yellow
var yPos = 90
for i in 0..<array.count {
let element = array[i]
let labelNum = UILabel()
let num1Nnum2 = "number 1 : \(element)"
labelNum.text = num1Nnum2
labelNum.textAlignment = .center
labelNum.frame = CGRect( x:10, y:yPos, width:250, height: 80)
yPos += 80
myText.removeFromSuperview()
enterButton.removeFromSuperview()
doneButton.removeFromSuperview()
self.view.addSubview(labelNum)
}
}
else
{
view.backgroundColor = .green
setUpMyText()
setUpEnterButton()
setUpDoneButton()
}
}
private func setUpMyText() {
self.view.addSubview(myText)
myText.translatesAutoresizingMaskIntoConstraints = false
myText.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
myText.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
myText.widthAnchor.constraint(equalToConstant: myText.bounds.width).isActive = true
myText.heightAnchor.constraint(equalToConstant: myText.bounds.height).isActive = true
}
private func setUpEnterButton() {
self.view.addSubview(enterButton)
enterButton.translatesAutoresizingMaskIntoConstraints = false
enterButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
enterButton.topAnchor.constraint(equalTo: myText.bottomAnchor, constant: 10).isActive = true
}
private func setUpDoneButton() {
self.view.addSubview(doneButton)
doneButton.translatesAutoresizingMaskIntoConstraints = false
doneButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
doneButton.topAnchor.constraint(equalTo: enterButton.bottomAnchor, constant: 10).isActive = true
}
#objc fileprivate func btnEnter() {
print(myText)
array.append(myText.text!)
myText.text = ""
}
#objc fileprivate func btnDone() {
print("Done")
self.viewDidLoad()
}