The shadow added to the view created is not appearing - swift

I am adding programatically a UIView, and setting its contsraints using NSLayoutConstraint as below, yet teh shadow is not being added.
For the shadow i am using SwifterSwift .addShadow()
UiView:
lazy var alertViewNew: UIView = {
let view = UIView()
view.layer.zPosition = 1
view.cornerRadius = 20
view.addShadow(ofColor: .lightGray, radius: 3, offset: .zero, opacity: 0.3)
view.translatesAutoresizingMaskIntoConstraints = false
return alertView
}()
Adding the Constaraints
func setUpAlertView() {
[alertViewNew].forEach {
(view.addSubview($0))
}
NSLayoutConstraint.activate([
alertViewNew.centerYAnchor.constraint(equalTo: view.centerYAnchor),
alertViewNew.centerXAnchor.constraint(equalTo: view.centerXAnchor),
alertViewNew.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
alertViewNew.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
titleLabel.leadingAnchor.constraint(equalTo: alertViewNew.leadingAnchor, constant: 20),
titleLabel.trailingAnchor.constraint(equalTo: alertViewNew.trailingAnchor, constant: -20),
titleLabel.topAnchor.constraint(equalTo: alertViewNew.topAnchor, constant: 20),
descriptionLabel.leadingAnchor.constraint(equalTo: alertViewNew.leadingAnchor, constant: 20),
descriptionLabel.trailingAnchor.constraint(equalTo: alertViewNew.trailingAnchor, constant: -20),
descriptionLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 20),
updateButton.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: 5),
updateButton.trailingAnchor.constraint(equalTo: alertViewNew.trailingAnchor, constant: -20),
updateButton.widthAnchor.constraint(equalToConstant: 65),
updateButton.bottomAnchor.constraint(equalTo: alertViewNew.bottomAnchor, constant: -20),
])
}
AddShadow by Swifter Swift
func addShadow(ofColor color: UIColor = UIColor(red: 0.07, green: 0.47, blue: 0.57, alpha: 1.0), radius: CGFloat = 3, offset: CGSize = .zero, opacity: Float = 0.5) {
layer.shadowColor = color.cgColor
layer.shadowOffset = offset
layer.shadowRadius = radius
layer.shadowOpacity = opacity
layer.masksToBounds = false
}
Things i tried to fix the issue
Setting mask to bound to true
setting is opaque to true
and some other trials found on stackoverflow
None of this worked

It's a bit difficult to help, because the code you've shown is incomplete (and has errors, as written).
For example, I assume your func addShadow is in a UIView extension like this:
extension UIView {
func addShadow(ofColor color: UIColor = UIColor(red: 0.07, green: 0.47, blue: 0.57, alpha: 1.0), radius: CGFloat = 3, offset: CGSize = .zero, opacity: Float = 0.5) {
layer.shadowColor = color.cgColor
layer.shadowOffset = offset
layer.shadowRadius = radius
layer.shadowOpacity = opacity
// no need for this
//layer.masksToBounds = false
}
}
Next, your lazy var alertViewNew:
lazy var alertViewNew: UIView = {
let view = UIView()
// no logical reason for this
//view.layer.zPosition = 1
// .cornerRadius is not a property of `UIView`
//view.cornerRadius = 20
// assuming this is in a UIView extension
view.addShadow(ofColor: .lightGray, radius: 3, offset: .zero, opacity: 0.3)
view.translatesAutoresizingMaskIntoConstraints = false
// no such thing as alertView
//return alertView
return view
}()
However... if we assume you have code that actually works (labels are defined and created somewhere, subviews are added correctly, etc), the most likely reason you're not seeing the shadow is because your alertViewNew probably has a clear background. If it is clear, there is nothing there to "cast a shadow."
Try setting alertViewNew.backgroundColor = .white and see if that fixes the problem.
Or, try this working example:
class CustomAlertTestVC: UIViewController {
lazy var alertViewNew: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(alertViewNew)
setUpAlertView()
}
func setUpAlertView() {
let titleLabel = UILabel()
let descriptionLabel = UILabel()
let updateButton = UIButton()
titleLabel.font = .boldSystemFont(ofSize: 16.0)
titleLabel.text = "New Version Available"
descriptionLabel.font = .systemFont(ofSize: 16.0)
descriptionLabel.numberOfLines = 0
descriptionLabel.text = "Please, Update application to the new version to continue."
updateButton.setTitle("UPDATE", for: [])
updateButton.setTitleColor(.systemBlue, for: [])
[titleLabel, descriptionLabel, updateButton].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
alertViewNew.addSubview($0)
}
NSLayoutConstraint.activate([
alertViewNew.centerYAnchor.constraint(equalTo: view.centerYAnchor),
// no need for centerX since we're adding leading and trailing constraints
//alertViewNew.centerXAnchor.constraint(equalTo: view.centerXAnchor),
alertViewNew.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10),
alertViewNew.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10),
titleLabel.leadingAnchor.constraint(equalTo: alertViewNew.leadingAnchor, constant: 20),
titleLabel.trailingAnchor.constraint(equalTo: alertViewNew.trailingAnchor, constant: -20),
titleLabel.topAnchor.constraint(equalTo: alertViewNew.topAnchor, constant: 20),
descriptionLabel.leadingAnchor.constraint(equalTo: alertViewNew.leadingAnchor, constant: 20),
descriptionLabel.trailingAnchor.constraint(equalTo: alertViewNew.trailingAnchor, constant: -20),
descriptionLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 20),
updateButton.topAnchor.constraint(equalTo: descriptionLabel.bottomAnchor, constant: 5),
updateButton.trailingAnchor.constraint(equalTo: alertViewNew.trailingAnchor, constant: -20),
// really no need for width constraint
//updateButton.widthAnchor.constraint(equalToConstant: 65),
updateButton.bottomAnchor.constraint(equalTo: alertViewNew.bottomAnchor, constant: -20),
])
alertViewNew.layer.shadowColor = UIColor.lightGray.cgColor
alertViewNew.layer.shadowOffset = .zero
alertViewNew.layer.shadowRadius = 3.0
alertViewNew.layer.shadowOpacity = 0.3
alertViewNew.layer.cornerRadius = 20.0
// to get the view's layer to "cast a shadow"
// either set the view's backgroundColor
alertViewNew.backgroundColor = .white
// or, set the layer's backgroundColor
//alertViewNew.layer.backgroundColor = UIColor.white.cgColor
}
}
Output:

Related

How to layout 2 StackView of different sizes in a ScrollView

I am trying to fit 2 stackView in one ScrollView
I decided to create a generic StackView that will contain the other two StackViews and place it in a ScrollView
But my left StackView contains 1 item and the second contains 2 items
Code bellow:
let categoryViewsForLeftColumn = categoryViews.split()[0]
let categoryViewsForRightColumn = categoryViews.split()[1]
let leftColumnStackView = UIStackView(arrangedSubviews: categoryViewsForLeftColumn)
leftColumnStackView.translatesAutoresizingMaskIntoConstraints = false
leftColumnStackView.axis = .vertical
leftColumnStackView.spacing = 20
leftColumnStackView.distribution = .fillEqually
let rightColumnStackView = UIStackView(arrangedSubviews: categoryViewsForRightColumn)
rightColumnStackView.translatesAutoresizingMaskIntoConstraints = false
rightColumnStackView.axis = .vertical
rightColumnStackView.spacing = 20
rightColumnStackView.distribution = .fillEqually
let generalStackView = UIStackView(arrangedSubviews: [leftColumnStackView, rightColumnStackView])
generalStackView.translatesAutoresizingMaskIntoConstraints = false
generalStackView.axis = .horizontal
generalStackView.spacing = 20
generalStackView.distribution = .fillEqually
categoriesScrollView.addSubview(generalStackView)
leftColumnStackView.backgroundColor = .green
rightColumnStackView.backgroundColor = .red
NSLayoutConstraint.activate([
generalStackView.widthAnchor.constraint(equalTo: categoriesScrollView.widthAnchor, constant: -10),
generalStackView.leadingAnchor.constraint(equalTo: categoriesScrollView.leadingAnchor, constant: 5),
generalStackView.trailingAnchor.constraint(equalTo: categoriesScrollView.trailingAnchor, constant: -5),
generalStackView.topAnchor.constraint(equalTo: categoriesScrollView.topAnchor, constant: 5),
generalStackView.bottomAnchor.constraint(equalTo: categoriesScrollView.bottomAnchor, constant: -5)
])
result bellow:
I expect items to be the same size
I was trying to post 2 StackView to ScrollView
code bellow:
categoriesScrollView.addSubview(leftColumnStackView)
categoriesScrollView.addSubview(rightColumnStackView)
leftColumnStackView.backgroundColor = .green
rightColumnStackView.backgroundColor = .red
NSLayoutConstraint.activate([
leftColumnStackView.leadingAnchor.constraint(equalTo: categoriesScrollView.leadingAnchor, constant: 5),
leftColumnStackView.trailingAnchor.constraint(equalTo: categoriesScrollView.centerXAnchor, constant: -5),
leftColumnStackView.topAnchor.constraint(equalTo: categoriesScrollView.topAnchor, constant: 5),
leftColumnStackView.bottomAnchor.constraint(equalTo: categoriesScrollView.bottomAnchor, constant: -5),
rightColumnStackView.leadingAnchor.constraint(equalTo: categoriesScrollView.centerXAnchor, constant: 5),
rightColumnStackView.trailingAnchor.constraint(equalTo: categoriesScrollView.trailingAnchor, constant: -5),
rightColumnStackView.topAnchor.constraint(equalTo: categoriesScrollView.topAnchor, constant: 5),
rightColumnStackView.bottomAnchor.constraint(equalTo: categoriesScrollView.bottomAnchor, constant: -5)
])
But it only got worse
result bellow:
The result I want to achieve:
Does anyone know how to achieve this?
If you want to create a "grid" like that without using a collection view (and there are many good reasons not to), you can do it with stack views.
However, instead of think in terms of a horizontal stack view with two vertical "column" stack views, think about a vertical stack view with "rows" of horizontal stack views.
Here's a quick example...
First, a custom view with rounded sides, an image view and a label:
class PillView: UIView {
let imgView = UIImageView()
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
label.numberOfLines = 0
imgView.translatesAutoresizingMaskIntoConstraints = false
label.translatesAutoresizingMaskIntoConstraints = false
addSubview(imgView)
addSubview(label)
NSLayoutConstraint.activate([
imgView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16.0),
imgView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: 12.0),
imgView.bottomAnchor.constraint(lessThanOrEqualTo: bottomAnchor, constant: -12.0),
imgView.centerYAnchor.constraint(equalTo: centerYAnchor),
imgView.widthAnchor.constraint(equalToConstant: 36.0),
imgView.heightAnchor.constraint(equalTo: imgView.widthAnchor),
label.topAnchor.constraint(equalTo: topAnchor, constant: 8.0),
label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8.0),
label.leadingAnchor.constraint(equalTo: imgView.trailingAnchor, constant: 8.0),
label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16.0),
])
layer.borderColor = UIColor.lightGray.cgColor
layer.borderWidth = 1
}
override var bounds: CGRect {
get { return super.bounds }
set(newBounds) {
super.bounds = newBounds
layer.cornerRadius = newBounds.size.height / 2.0
}
}
}
Now, a sample controller:
class SampleViewController: UIViewController {
let numViews: Int = 5
override func viewDidLoad() {
super.viewDidLoad()
let outerVerticalStack = UIStackView()
outerVerticalStack.axis = .vertical
outerVerticalStack.spacing = 20
outerVerticalStack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(outerVerticalStack)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
outerVerticalStack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
outerVerticalStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
outerVerticalStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
])
var j: Int = 0
while j < numViews {
let rowStack = UIStackView()
rowStack.axis = .horizontal
rowStack.spacing = 20
rowStack.distribution = .fillEqually
let v = PillView()
if j == 2 {
v.label.text = "View \(j)\ntwo lines"
} else {
v.label.text = "View \(j)"
}
if let img = UIImage(systemName: "\(j).square.fill") {
v.imgView.image = img
}
rowStack.addArrangedSubview(v)
j += 1
if j < numViews {
let v = PillView()
v.label.text = "View \(j)"
if let img = UIImage(systemName: "\(j).square.fill") {
v.imgView.image = img
}
rowStack.addArrangedSubview(v)
} else {
let v = UIView()
rowStack.addArrangedSubview(v)
}
j += 1
outerVerticalStack.addArrangedSubview(rowStack)
}
}
}
The result looks like this:

Same constraints different results

I gave a value of -8 to the "bottom to Safe Area bottom" constraints of 2 views, but they are not showing at the same distance from the Safe Area (seems like one needs -16 to equalize them).
What could be the issue?
Here's some code:
func addPlayerViews() { // called in viewDidLoad
DispatchQueue.main.async {
self.smallView.backgroundColor = .clear
self.smallView.myLittleSubview.backgroundColor = .white
self.smallView.myLittleSubview.layer.cornerRadius = 4
self.smallView.myLittleSubview.layer.shadowColor = myShadowColor
self.smallView.myLittleSubview.layer.shadowOffset = CGSize(width: 0.0, height: 3.0)
self.smallView.myLittleSubview.layer.masksToBounds = false
self.smallView.myLittleSubview.layer.shadowOpacity = 1.0
self.smallView.myLittleSubview.layer.shadowRadius = 4
self.bigView.backgroundColor = .white
self.bigView.layer.cornerRadius = 4
self.bigView.layer.shadowColor = myShadowColor
self.bigView.layer.shadowOffset = CGSize(width: 0.0, height: -3.0)
self.bigView.layer.masksToBounds = false
self.bigView.layer.shadowOpacity = 1.0
self.bigView.layer.shadowRadius = 4
self.view.addSubview(self.smallView)
self.view.addSubview(self.bigView)
self.smallView.translatesAutoresizingMaskIntoConstraints = false
self.bigView.translatesAutoresizingMaskIntoConstraints = false
let safeArea = self.view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
self.smallView.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor, constant: 4),
self.smallView.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor, constant: -4),
self.smallView.bottomAnchor.constraint(equalTo: safeArea.bottomAnchor, constant: -8),
self.smallView.heightAnchor.constraint(equalToConstant: 48),
self.bigView.leadingAnchor.constraint(
equalTo: self.smallView.myLittleSubview.leadingAnchor, constant: 0),
self.bigView.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor, constant: -4),
self.bigView.bottomAnchor.constraint(equalTo: safeArea.bottomAnchor, constant: -8),
// ☝️ not working as expected. See: 👉 https://stackoverflow.com/q/62602071/5306470
self.bigView.heightAnchor.constraint(equalToConstant: 270)
])
self.view.layoutIfNeeded() // must be at end of animation block, it seems
}
}
Screenshot
Big view is blue and semi-transparent, myLittleSubview is orange, and smallView is .clear
iPhone 11 Pro Max (13.5)

Programatically created UIPageControl not showing

In my view hierarchy, I have a UIPageViewController (inside a container view). Underneath that is the UIPageControl and at the bottom is a stack view consisting of a text view and a button. I see the UIPageViewController and the stack view but not the UIPageControl. Any idea what I am doing wrong:
// Page view controller
introPageViewC = IntroPageViewC()
addChild(introPageViewC)
introPageViewC.view.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(introPageViewC.view)
NSLayoutConstraint.activate([
introPageViewC.view.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 0.0),
introPageViewC.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 0.0),
introPageViewC.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 0.0),
introPageViewC.view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: 0.0),
])
introPageViewC.didMove(toParent: self)
// Page view control
introPageControl.currentPageIndicatorTintColor = UIColor.orange
introPageControl.pageIndicatorTintColor = UIColor.lightGray.withAlphaComponent(0.8)
view.addSubview(introPageControl)
introPageControl.translatesAutoresizingMaskIntoConstraints = false
introPageControl.topAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 10).isActive = true
introPageControl.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
// Stack view
view.addSubview(stackView)
stackView.axis = .vertical
stackView.distribution = .fillEqually
stackView.spacing = 30
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.topAnchor.constraint(equalTo: introPageControl.bottomAnchor, constant: 10).isActive = true
stackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 40).isActive = true
stackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -40).isActive = true
Expected output:
Edit:
Attempt at adding to the stack view:
var allViews = [UIView]()
// Adding to stackview
introPageControl.currentPageIndicatorTintColor = UIColor.orange
introPageControl.pageIndicatorTintColor = UIColor.lightGray.withAlphaComponent(0.8)
allViews.append(introPageControl)
nameTextField = UITextField(frame: CGRect(x: 0, y: 0, width: 120, height: 40))
nameTextField.placeholder = "Mealplan name"
Utilities.styleTextField(nameTextField)
nameTextField.setPadding()
allViews.append(nameTextField)
let nextButton = UIButton(type: .system)
nextButton.frame = CGRect(x: 20, y: 20, width: 100, height: 40)
nextButton.setTitle("Next", for: .normal)
nextButton.titleLabel?.textColor = .white
nextButton.titleLabel?.font = UIFont(name: "NexaBold", size: 16)
Utilities.styleDefaultButton(nextButton)
nextButton.addTarget(self, action: #selector(tapSubmit(_:)), for: .touchUpInside)
allViews.append(nextButton)
errorLabel.frame = CGRect(x: 20, y: 20, width: 100, height: 40)
errorLabel.font = UIFont(name: "NexaBold", size: 16)
errorLabel.textColor = .systemRed
errorLabel.textAlignment = .center
errorLabel.alpha = 0
allViews.append(errorLabel)
for eachView in allViews {
stackView.addArrangedSubview(eachView)
}
introPageControl.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
I believe you meant centerXAnchor?
I think you've got the topAnchor all wrong. Right now, it seems to be constrained to the bottom of the containerView plus 10, which is just off the screen. I think you meant to say -10.
introPageControl.topAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -10).isActive = true

Entering text into textfield causing uipangesture object to move back to its orginal position

My swift code below has a image view connected to a pangesture. When something is entered into a textfield when after the image view is moved. The image view reverts back to its original position.The gif represents that what is going on. I just don't want the effect of the pangesutre to be nullified after text is entered into the textfield.
LINK TO GITHUB https://github.com/redrock34/sse
import UIKit
class ViewController: UIViewController {
var pic = UIImageView()
let fight = (0..<10).map { _ in UIImageView() }
var textEnter = UITextField()
var g2 = UIPanGestureRecognizer()
var slider = UISlider()
override func viewDidLoad() {
super.viewDidLoad()
fight[0].image = UIImage(named: "a.png")
fight.forEach{
$0.isUserInteractionEnabled = true
}
[slider,textEnter].forEach{
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
$0.backgroundColor = .blue
}
slider.backgroundColor = .clear
g2 = UIPanGestureRecognizer(target: self, action: #selector(ViewController.g1Method))
fight[0].addGestureRecognizer(g2)
pic.backgroundColor = .clear
pic.backgroundColor = .systemGreen
fight.forEach{
$0.backgroundColor = .clear
view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
[pic].forEach{
view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
// Do any additional setup after loading the view.
NSLayoutConstraint.activate ([
pic.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant :0),
pic.topAnchor.constraint(equalTo: fight[0].bottomAnchor, constant : 0),
pic.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.62, constant: 0),
pic.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
textEnter.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant :0),
textEnter.topAnchor.constraint(equalTo: view.topAnchor, constant : 0),
textEnter.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.1, constant: 0),
textEnter.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
fight[0].trailingAnchor.constraint(equalTo: view.trailingAnchor, constant :0),
fight[0].topAnchor.constraint(equalTo: textEnter.bottomAnchor, constant : 0),
fight[0].heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.10, constant: 0),
fight[0].widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.10, constant: 0),
fight[0].leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
slider.topAnchor.constraint(equalTo: pic.bottomAnchor, constant : 0),
slider.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.08, constant: 0),
slider.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1, constant: 0),
slider.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
])
textEnter.textAlignment = .center
self.view.sendSubviewToBack(pic)
}
#objc func g1Method(_ sender: UIPanGestureRecognizer){
let tranistioon = sender.translation(in: self.view)
sender.view!.center = CGPoint(x: sender.view!.center.x + tranistioon.x, y: sender.view!.center.y + tranistioon.y)
sender.setTranslation(CGPoint.zero,in: self.view) }
}
Try creating a class of UIImageVIew and write the following code:
import UIKit
class draggableImage:UIImageView {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.layer.borderWidth = 1
self.layer.borderColor = UIColor.red.cgColor
self.isUserInteractionEnabled = true
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first;
let location = touch?.location(in: self.superview);
if(location != nil)
{
self.frame.origin = CGPoint(x: location!.x-self.frame.size.width/2, y: location!.y-self.frame.size.height/2);
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
}
}
Don't forget to assign the class draggableImage to the Image View from the Attribute Menu.
You cannot mix explicit frame setting with auto-layout constraints for the same object.
For example, if you:
add a label to the main view
set label.translatesAutoresizingMaskIntoConstraints = false
set constraints for the label
then, via code...
change the .center property of the label
you will see the label move, but when the next UI update happens (you edit a text field, tap a button, rotate the device, etc), auto-layout will reset the frame of the label based on its constraints.
So, in your pan gesture handler, you can either update the .constant values for the fight[0] object (instead of changing its .center), or...
You can leave label.translatesAutoresizingMaskIntoConstraints = true for your fight objects and explicitly set their frames and centers.
Note: in either case, you do not want to constrain any other elements relative to the fight objects, or they will move when you move fight[0].
Here is a modification to your ViewController class (from your GitHub zip), implementing the method of not using auto-layout constraints on your fight objects.
class ViewController: UIViewController {
var pic = UIImageView()
let fight = (0..<10).map { _ in UIImageView() }
var textEnter = UITextField()
var g2 = UIPanGestureRecognizer()
var slider = UISlider()
override func viewDidLoad() {
super.viewDidLoad()
fight[0].image = UIImage(named: "a.png")
fight.forEach{
$0.isUserInteractionEnabled = true
}
[slider,textEnter].forEach{
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
$0.backgroundColor = .blue
}
slider.backgroundColor = .clear
g2 = UIPanGestureRecognizer(target: self, action: #selector(ViewController.g1Method))
fight[0].addGestureRecognizer(g2)
pic.backgroundColor = .systemGreen
fight.forEach{
$0.backgroundColor = .clear
view.addSubview($0)
// do NOT use auto-layout for fight views
//$0.translatesAutoresizingMaskIntoConstraints = false
}
[pic].forEach{
view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
// need a non-rendering "spacer" to vertically separate textEnter from Pic
let spacer = UILayoutGuide()
view.addLayoutGuide(spacer)
// NOTE: do NOT constrain any elements relative to fight views
NSLayoutConstraint.activate ([
// constrain textEnter top / leading / trailing to view
textEnter.topAnchor.constraint(equalTo: view.topAnchor, constant : 0),
textEnter.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
textEnter.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant :0),
// constrain textEnter height to 0.1 * view height
textEnter.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.1, constant: 0),
// constrain spacer top to bottom of textEnter
spacer.topAnchor.constraint(equalTo: textEnter.bottomAnchor, constant: 0.0),
// constrain spacer leading to view leading
spacer.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0.0),
// constrain spacer height to 0.1 * view height
spacer.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.10),
// spacer width doesn't matter
spacer.widthAnchor.constraint(equalToConstant: 1.0),
// constrain pic Top to spacer bottom
pic.topAnchor.constraint(equalTo: spacer.bottomAnchor, constant: 0.0),
// constrain pic leading / trailing to view
pic.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
pic.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant :0),
// constrain pic height as you had it
pic.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.62, constant: 0),
// slider constraints
slider.topAnchor.constraint(equalTo: pic.bottomAnchor, constant : 0),
slider.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.08, constant: 0),
slider.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1, constant: 0),
slider.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant : 0),
])
textEnter.textAlignment = .center
self.view.sendSubviewToBack(pic)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// set fight[0] frame *after* textEnter has been laid-out
fight[0].frame.size = CGSize(width: view.frame.width * 0.10, height: view.frame.height * 0.10)
let x = view.frame.origin.x
let y = textEnter.frame.origin.y + textEnter.frame.size.height
fight[0].frame.origin = CGPoint(x: x, y: y)
}
#objc func g1Method(_ sender: UIPanGestureRecognizer){
let tranistioon = sender.translation(in: self.view)
sender.view!.center = CGPoint(x: sender.view!.center.x + tranistioon.x, y: sender.view!.center.y + tranistioon.y)
sender.setTranslation(CGPoint.zero,in: self.view)
}
}
Use this method instead
var existingTransition : CGAffineTransform?
#objc func g1Method(_ sender: UIPanGestureRecognizer){
guard let child = sender.view else{return}
let transitionPoint = sender.translation(in: self.view)
let newTransition = CGAffineTransform(translationX: transitionPoint.x, y: transitionPoint.y)
switch sender.state {
case .ended,.cancelled:// on End
if let existing = existingTransition{
self.existingTransition = newTransition.concatenating(existing)
}else{
self.existingTransition = newTransition
}
default://on change and other states
if let existing = existingTransition{
child.transform = newTransition
.concatenating(existing)
}else{
child.transform = newTransition
}
}
self.view.layoutIfNeeded()
}
Sorry if my code is messy. But I checked some scenaios its working fine.
happy codding

Gradient color for text to UITextView

I need to set gradient color with to colors into UITextView with white background color like in instagram stories. Example below:
Ignore the constraints set in the following code, but the concept should go like this:
containerView = GradientView.init()
self.view.addSubview(containerView)
containerView.translatesAutoresizingMaskIntoConstraints = false
containerView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0).isActive = true
containerView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0).isActive = true
containerView.widthAnchor.constraint(equalToConstant: 220).isActive = true
containerView.heightAnchor.constraint(equalToConstant: 50).isActive = true
containerView.backgroundColor = .white
textView = UITextView()
containerView.addSubview(textView)
textView.translatesAutoresizingMaskIntoConstraints = false
textView.leftAnchor.constraint(equalTo: containerView.leftAnchor, constant: 0).isActive = true
textView.rightAnchor.constraint(equalTo: containerView.rightAnchor, constant: 0).isActive = true
textView.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 0).isActive = true
textView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: 0).isActive = true
textView.text = "#SomeValue"
textView.font = UIFont.systemFont(ofSize: 22, weight: .bold)
containerView.layer.mask = textView.layer.sublayers?.last
where GradientView is a UIView subclass similar to :
class GradientView: UIView{
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
func addGradient(){
let gradient = CAGradientLayer()
gradient.frame = self.bounds
gradient.colors = [UIColor.blue.cgColor,UIColor.red.cgColor,UIColor.green.cgColor]
gradient.startPoint = CGPoint(x: 0, y: 1)
gradient.endPoint = CGPoint(x: 1, y: 0)
gradient.locations = [0,0.5,1]
self.layer.addSublayer(gradient)
}
}
Should look something like this. Maybe your gradient colours would look better.