Whole content out of view - ios

I have a Shuffle package added to my project (https://cocoapods.org/pods/Shuffle-iOS), the package works fine, but the problem is that even though I set cards width and height to my UIView, cards are out of UIView anyways, I tried changing the frame of my cards and set width and height to UIViews, but they are still out of UIView any solutions?
my UIView is mainView in code below
func card1(index: swipeCardData) -> SwipeCard {
let card = SwipeCard()
card.swipeDirections = [.left, .right, .up]
card.layer.cornerRadius = 12
card.layer.shadowOffset = CGSize.zero
card.layer.shadowOpacity = 1.0
card.layer.shadowRadius = 6.0
card.layer.masksToBounds = false
card.layer.borderWidth = 2
let view_bg = UIView(frame: CGRect(x: 16, y: 60, width: mainView.frame.size.width, height: mainView.frame.height)) // here is set cards width and frame to my UIView
card.content = view_bg
view_bg.layer.cornerRadius = 12
view_bg.clipsToBounds = true
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [self] in
let view_bg1 = UIView(frame: CGRect(x: 0, y: 0, width: view_bg.frame.size.width, height: view_bg.frame.size.height))
card.content?.addSubview(view_bg1)
let img_card_type = UIImageView(frame: CGRect.zero)
img_card_type.contentMode = .scaleAspectFit
img_card_type.translatesAutoresizingMaskIntoConstraints = false
img_card_type.isHidden = true
view_bg1.addSubview(img_card_type)
img_card_type.centerXAnchor.constraint(equalToSystemSpacingAfter: view_bg1.centerXAnchor, multiplier: 1).isActive = true
img_card_type.topAnchor.constraint(equalTo: view_bg1.topAnchor, constant: 0).isActive = true
img_card_type.widthAnchor.constraint(equalToConstant: 100).isActive = true
pictures for better understanding :
as you can see on the screenshot above the card content is out of mainView which is in the background(gray box)
the end result below

The reason is you are not providing height for image view and telling to expand according to aspect ratio of image. set a max height for image view. to better UX centre imageview in both axis and a fixed either height or width and a maximum for other width or height.
img_card_type.centerXAnchor.constraint(equalToSystemSpacingAfter: view_bg1.centerXAnchor, multiplier: 1).isActive = true
img_card_type.centerYAnchor.constraint(equalToSystemSpacingAfter: view_bg1.centerYAnchor, multiplier: 1).isActive = true
img_card_type.widthAnchor.constraint(equalToConstant: 100).isActive = true
img_card_type.heightAnchor.constraint(lessThanOrEqualToConstant: 100).isActive = true

Related

My textView bottomAnchor does not seem to work?

I have a textView and I have a line, I set the line's frame without contraints and set textView frame with constraints. Simply what I want is the textView to follow the line, so I put a bottomAnchor to textView equal to the topAnchor of the line. Yet when I animate the line the textView does not follow? What am I doing wrong?
var button = UIButton()
var testLine = UIView()
let textView = UITextView()
var textViewBottomAnchorConstraint: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
testLine.backgroundColor = .black
testLine.frame = CGRect(x: 0, y: 335, width: UIScreen.main.bounds.width, height: 10)
view.addSubview(testLine)
view.addSubview(textView)
textView.frame = .zero//CGRect(x: CGFloat(integerLiteral: 16), y: CGFloat(integerLiteral: 300), width: CGFloat(integerLiteral: 282), height: CGFloat(integerLiteral: 35))
textView.backgroundColor = UIColor.yellow
textView.text = ""
textView.font = UIFont(name: "Arial Rounded MT Bold", size: 15)
textView.translatesAutoresizingMaskIntoConstraints = false
textView.isHidden = false
textView.translatesAutoresizingMaskIntoConstraints = false
// textView.bottomAnchor.constraint(equalTo: testLine.topAnchor, constant: 0).isActive = true
textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor, constant: 20).isActive = true
textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor, constant: -20).isActive = true
textView.heightAnchor.constraint(equalToConstant: 40).isActive = true
textViewBottomAnchorConstraint = textView.bottomAnchor.constraint(equalTo: testLine.topAnchor, constant: 0)
textViewBottomAnchorConstraint?.isActive = true
UIView.animate(withDuration: 2, delay: 2, options: .curveEaseIn, animations: {
self.testLine.transform = CGAffineTransform.identity.translatedBy(x: 0, y: 30)
}) { (true) in
self.view.layoutIfNeeded()
}
}
As #Vollan correctly said animating transform property is not the best option. Here is quote from Apple documentation: "In iOS 8.0 and later, the transform property does not affect Auto Layout. Auto layout calculates a view’s alignment rectangle based on its untransformed frame." Therefore animation of transform property doesn't change layout of textView. I recommend you to animate frame property instead of transform.
However, if you switch to frame animation it doesn't fix all your problems. If you keep your animation inside viewDidLoad method you may encounter very strange behavior. The reason is that in viewDidLoad the view itself is not yet laid out properly. Starting animation inside viewDidLoad may lead to unpredicted results.
At last you need adjust your animation block. Apple recommends to apply layoutIfNeeded inside the animation block. Or at least they used to recommend it then autolayout was introduced - watch this WWDC video (starting from 30th minute) for further details.
If you apply all recommendations above your code should look like this:
var button = UIButton()
var testLine = UIView()
let textView = UITextView()
var textViewBottomAnchorConstraint: NSLayoutConstraint?
var triggeredAnimation = false
override func viewDidLoad() {
super.viewDidLoad()
testLine.backgroundColor = .black
testLine.frame = CGRect(x: 0, y: 335, width: UIScreen.main.bounds.width, height: 10)
view.addSubview(testLine)
view.addSubview(textView)
textView.frame = .zero//CGRect(x: CGFloat(integerLiteral: 16), y: CGFloat(integerLiteral: 300), width: CGFloat(integerLiteral: 282), height: CGFloat(integerLiteral: 35))
textView.backgroundColor = UIColor.yellow
textView.text = ""
textView.font = UIFont(name: "Arial Rounded MT Bold", size: 15)
textView.translatesAutoresizingMaskIntoConstraints = false
textView.isHidden = false
textView.translatesAutoresizingMaskIntoConstraints = false
// textView.bottomAnchor.constraint(equalTo: testLine.topAnchor, constant: 0).isActive = true
textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor, constant: 20).isActive = true
textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor, constant: -20).isActive = true
textView.heightAnchor.constraint(equalToConstant: 40).isActive = true
textViewBottomAnchorConstraint = textView.bottomAnchor.constraint(equalTo: testLine.topAnchor, constant: 0)
textViewBottomAnchorConstraint?.isActive = true
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// viewDidAppear may be called several times during view controller lifecycle
// triggeredAnimation ensures that animation will be called just once
if self.triggeredAnimation {
return
}
self.triggeredAnimation = true
let oldFrame = self.testLine.frame
UIView.animate(withDuration: 2, delay: 2, options: .curveEaseIn, animations: {
self.testLine.frame = CGRect(x: oldFrame.minX, y: oldFrame.minY + 30, width: oldFrame.width,
height: oldFrame.height)
self.view.layoutIfNeeded()
})
}
Anchor points make references to others positions, meaning. It is still referensed to y = 355 as you transform it and not actually "move" it.
What i recommend is that you don't mix using frame-based layout and anchorpoints / layout constraints.

how to add image view with some constraints programmatically using swift?

I am new in iOS Development. If using storyboard, I can place an Image view in view controller like this
I need to make something like that programmatically.
so I have custom view from a library called RevealingSplashView , but I need to add an image view to that custom UI View. I just know to add the image view, maybe something like this
let imageName = "yourImage.png"
let image = UIImage(named: imageName)
let imageView = UIImageView(image: image!)
imageView.frame = CGRect(x: 0, y: 0, width: 100, height: 200)
revealingSplashView.addSubview(imageView)
but I don't know how to set that constraint to image view to
a. align to center x to superview
b. proportional width to superview 0.8
c. height constraint = 25
d. align bottom to safe area = 32
how to do that ?
here is the code I use before want to add image view
let screenSize = UIScreen.main.bounds
let iconWidth = (screenSize.width) * 0.8
let iconHeight = iconWidth * 1 // ratio 1:1
revealingSplashView = RevealingSplashView(iconImage: UIImage(named: "Loading Page Asset")!,iconInitialSize: CGSize(width: iconWidth, height: iconHeight), backgroundColor: AppColor.mainYellow.getUIColor())
revealingSplashView.animationType = SplashAnimationType.twitter
revealingSplashView.imageView?.contentMode = .scaleAspectFill
// add loading indicator to RevealingSplashView Programatically
revealingSplashViewIndicator.color = UIColor.white
revealingSplashViewIndicator.frame = CGRect(x: 0.0, y: 0.0, width: 30.0, height: 30.0)
revealingSplashViewIndicator.center = CGPoint(x: self.view.center.x, y: self.view.center.y + (iconHeight/2) + 64 )
revealingSplashView.addSubview(revealingSplashViewIndicator)
revealingSplashViewIndicator.bringSubviewToFront(self.revealingSplashView)
revealingSplashViewIndicator.startAnimating()
let window = UIApplication.shared.keyWindow
window?.addSubview(revealingSplashView)
I recommend using anchors:
let imageName = "yourImage.png"
let image = UIImage(named: imageName)
let imageView = UIImageView(image: image!)
imageView.frame = CGRect(x: 0, y: 0, width: 100, height: 200)
revealingSplashView.addSubview(imageView)
// you need to turn off autoresizing masks (storyboards do this automatically)
imageView.translatesAutoresizingMaskIntoConstraints = false
// setup constraints, it is recommended to activate them through `NSLayoutConstraint.activate`
// instead of `constraint.isActive = true` because of performance reasons
NSLayoutConstraint.activate([
imageView.centerXAnchor.constraint(equalTo: revealingSplashView.centerXAnchor),
imageView.widthAnchor.constraint(equalTo: revealingSplashView.widthAnchor, multiplier: 0.8),
imageView.heightAnchor.constraint(equalToConstant: 25),
imageView.bottomAnchor.constraint(equalTo: revealingSplashView.safeAreaLayoutGuide.bottomAnchor, constant: -32),
])
To add constraints programmatically you need to set
imageView.translatesAutoresizingMaskIntoConstraints = false
then you can set the constraints:
imageView.widthAnchor.constraint(equalTo: revealingSplashView.widthAnchor, multiplier: 0.8).isActive = true
imageView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 25).isActive = true
imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
if you want to activate constraints you need to set
isActive = true
also if you support iOS < 11 you need to put a control because you don't have the safeArea
revealingSplashView.addSubview(imageView)
imageView.centerXAnchor.constraint(equalTo: revealingSplashView.centerXAnchor).isActive = true
imageView.widthAnchor.constraint(equalTo: revealingSplashView.widthAnchor, multiplier: 0.8).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 25).isActive = true
imageView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
imageView.translatesAutoresizingMaskIntoConstraints = false

Autolayout programmatic aspect ratio setting

I am trying to add a subview to view and define autolayout constraints, including aspect ratio. But aspect ratio that I see at runtime is not what I defined in constraints. What am I doing wrong? As you can see in code, background view height should be 0.5 of background view width, but that's not the case here in the screenshot. Here is my code:
class ViewController: UIViewController {
private var backgroundView:UIView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
view.backgroundColor = UIColor.orange
backgroundView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 100))
backgroundView?.backgroundColor = UIColor.black.withAlphaComponent(1.0)
backgroundView?.layer.borderColor = UIColor.white.cgColor
backgroundView?.layer.borderWidth = 1.5
backgroundView?.layer.cornerRadius = 4
backgroundView?.clipsToBounds = true
backgroundView?.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(backgroundView!)
backgroundView?.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1.0).isActive = true
backgroundView?.heightAnchor.constraint(equalTo: backgroundView!.widthAnchor, multiplier: 0.5).isActive = true
backgroundView?.centerXAnchor.constraint(equalTo: view!.centerXAnchor, constant: 0).isActive = true
backgroundView?.topAnchor.constraint(equalTo: view!.topAnchor, constant: 4).isActive = true
}
}
Here is the screenshot:
"background view height should be 0.5 of background view width"
Your screenshot size is 1334 x 750
Your backgroundView - including the border - is 1334 x 667
1334 * 0.5 == 667
So, you are getting exactly what you are asking for.
Try to change height constraint to set:
backgroundView?.heightAnchor.constraint(equalTo: view!.heightAnchor, multiplier: 0.5).isActive = true
NB: You are getting the exact result which you are looking for. It has the height that's half of its width. There is nothing wrong with the screenshot.

ios UIImage going outside of UIImageView Border

Here black border shows the Parent UIView of UIImageView and Red border showing UIImageView i'm downloading image from server but the image is going outside of the UIImageView area as shown in the image. I'm doing it programmatically any help would be very much appreciated. I'm adding code block below
let bottomView : UIView = UIView(frame: CGRect(x : 10, y: stackView.height, width: view.width * 0.75, height: view.width * 0.75 ))
view.addSubview(bottomView)
bottomView.layer.borderColor = UIColor.black.cgColor
bottomView.layer.borderWidth = 1
bottomView.translatesAutoresizingMaskIntoConstraints = false
bottomView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
bottomView.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: -20).isActive = true
bottomView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 10).isActive = true
bottomView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -10).isActive = true
bottomView.widthAnchor.constraint(equalToConstant: view.width * 0.75).isActive = true
bottomView.heightAnchor.constraint(equalToConstant: view.width * 0.75).isActive = true
let imageView : UIImageView = UIImageView(frame : CGRect(x: 0, y: 0, width: 250, height: 250 ))
imageView.layer.borderColor = UIColor.red.cgColor
imageView.layer.borderWidth = 1
bottomView.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.centerXAnchor.constraint(equalTo: bottomView.centerXAnchor).isActive = true
imageView.centerYAnchor.constraint(equalTo: bottomView.centerYAnchor).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 250).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 250).isActive = true
imageView.downloadedFrom(link: (sizeResult?.results![0].data?.size_Chart?.mobile_image?.imageValue?.imageMain?.url)!, contentMode : .scaleAspectFill)
this bottomView will be added UIAlertViewController.
This image shows ** contentMode is Aspect Fit **
You can use clip to bound with your image view, Definitely It will resolve your issue.
Swift:
override func viewDidLoad() {
super.viewDidLoad()
self.bottomView.clipsToBounds = false
self.imageView.clipsToBounds = true
}
Set the properties of uiimageview and content mode:
self.imageView.clipsToBounds = true
self.imageView.contentMode = .scaleAspectFit
imageView?.contentMode = .scaleAspectFit
self.imageView.clipsToBounds = true
it was worked for me..
The last line of your code should be this -
imageView.downloadedFrom(link: (sizeResult?.results![0].data?.size_Chart?.mobile_image?.imageValue?.imageMain?.url)!, contentMode : .scaleAspectFit)

How to size a UIScrollView to fit an unknown amount of text in a UILabel?

I have added a scrollview subview in one of my views, but am having trouble getting it's height to accurately fit the content that the scrollview is showing, which is text in the UILabel. The height needs to be dynamic (i.e. a factor of the text length), because I am instantiating this view for many different text lengths. Whenever I log label.frame.bounds I get (0,0) back. I have also tried sizeToFits() in a few places without much luck.
My goal is to get the scrollview to end when it reaches the last line of text. Also, I am using only programmatic constraints.
A condensed version of my code is the following:
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
let scrollView = UIScrollView()
let containerView = UIView()
let label = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
// This needs to change
scrollView.contentSize = CGSize(width: 375, height: 1000)
scrollView.addSubview(containerView)
view.addSubview(scrollView)
label.text = unknownAmountOfText()
label.backgroundColor = .gray
containerView.isUserInteractionEnabled = true
containerView.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scrollView.frame = view.bounds
containerView.frame = CGRect(x: 0, y: 0, width: scrollView.contentSize.width, height: scrollView.contentSize.height)
}
}
Any help is appreciated.
SOLUTION found:
func heightForLabel(text: String, font: UIFont, lineHeight: CGFloat, width: CGFloat) -> CGFloat {
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.setLineHeight(lineHeight: lineHeight)
label.sizeToFit()
return label.frame.height
}
I found this solution online, that gives me what I need to set the appropriate content size for the scrollView height based on the label's height. Ideally, I'd be able to determine this without this function, but for now I'm satisfied.
The key to UIScrollView and its content size is setting your constraints so that the actual content defines the contentSize.
For a simple example: say you have a UIScrollView with width: 200 and height: 200. Now you put a UIView inside it, that has width: 100 and height: 400. The view should scroll up and down, but not left-right. You can constrain the view to 100x400, and then "pin" the top, bottom, left and right to the sides of the scroll view, and AutoLayout will "auto-magically" set the scrollview's contentSize.
When you add subviews that can change size - either explicitly (code, user interaction) or implicitly - if the constraints are set correctly those changes will also "auto-magically" adjust the scrollview's contentSize.
So... here is an example of what you are trying to do:
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
let scrollView = UIScrollView()
let label = UILabel()
let s1 = "1. This is the first line of text in the label. It has words and punctuation, but no embedded line-breaks, so what you see here is normal UILabel word-wrapping."
var counter = 1
override func viewDidLoad() {
super.viewDidLoad()
// turn off translatesAutoresizingMaskIntoConstraints, because we're going to set them
scrollView.translatesAutoresizingMaskIntoConstraints = false
label.translatesAutoresizingMaskIntoConstraints = false
// set background colors, just so we can see the bounding boxes
self.view.backgroundColor = UIColor(red: 1.0, green: 0.7, blue: 0.3, alpha: 1.0)
scrollView.backgroundColor = UIColor(red: 0.8, green: 0.8, blue: 1.0, alpha: 1.0)
label.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
// add the label to the scrollView, and the scrollView to the "main" view
scrollView.addSubview(label)
self.view.addSubview(scrollView)
// set top, left, right constraints on scrollView to
// "main" view + 8.0 padding on each side
scrollView.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor, constant: 8.0).isActive = true
scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 8.0).isActive = true
scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -8.0).isActive = true
// set the height constraint on the scrollView to 0.5 * the main view height
scrollView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.5).isActive = true
// set top, left, right AND bottom constraints on label to
// scrollView + 8.0 padding on each side
label.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 8.0).isActive = true
label.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 8.0).isActive = true
label.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -8.0).isActive = true
label.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -8.0).isActive = true
// set the width of the label to the width of the scrollView (-16 for 8.0 padding on each side)
label.widthAnchor.constraint(equalTo: scrollView.widthAnchor, constant: -16.0).isActive = true
// configure label: Zero lines + Word Wrapping
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = UIFont.systemFont(ofSize: 17.0)
// set the text of the label
label.text = s1
// ok, we're done... but let's add a button to change the label text, so we
// can "see the magic" happening
let b = UIButton(type: UIButtonType.system)
b.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(b)
b.setTitle("Add a Line", for: .normal)
b.topAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 24.0).isActive = true
b.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
b.addTarget(self, action: #selector(self.btnTap(_:)), for: .touchUpInside)
}
func btnTap(_ sender: Any) {
if let t = label.text {
counter += 1
label.text = t + "\n\n\(counter). Another line"
}
}
}
give top,left,right and bottom constraint to label with containerView.
and
set label.numberOfLines = 0
also ensure that you have given top, left, right and bottom constraint to containerView. this will solve your issue
Set the auto layout constraints from the interface builder as shown in image .
enter image description here
I set the height of UIScrollView as 0.2 of the UIView
Then drag the UIlabel from MainStoryBoard to the view controller.
Add this two lines in viewdidload method.
draggedlabel.numberOfLines = 0
draggedlabel.lineBreakMode = NSLineBreakMode.byWordWrapping

Resources