I subclassed an UIView that is supposed to create it's owned constraints:
@IBDesignable class MyCtrl: UIView {
var label: UITextField!
var _internalLayout = false
public override init(frame: CGRect) {
super.init(frame: frame)
_init()
}
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
_init()
}
open override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
self._init()
self.setNeedsDisplay()
}
func _init() {
label = UITextField()
addSubview(label)
super.backgroundColor = .cyan
#if TARGET_INTERFACE_BUILDER
translatesAutoresizingMaskIntoConstraints = true
#else
translatesAutoresizingMaskIntoConstraints = false
#endif
}
override public func layoutSubviews() {
if _internalLayout {
_internalLayout = false
return
}
let theOrientation = orientation
setupConstraints(theOrientation)
super.layoutSubviews()
}
func setupConstraints(_ orientation: IosTraitClass) {
_internalLayout = true
superview?.removeConstraints(superview!.constraints)
if orientation == .CR {
label.text = "setupConstraints(.CR \(superview?.frame.size.width)"
label.sizeToFit()
superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .leading, relatedBy: .equal, toItem: superview , attribute: .leading , multiplier: 1, constant: 30))
superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: superview, attribute: .top, multiplier: 1, constant: 100))
superview?.addConstraint( NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: .none, attribute: .notAnAttribute, multiplier: 1, constant: (superview?.frame.size.width ?? 0)-60))
superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: .none, attribute: .notAnAttribute, multiplier: 1, constant: (superview?.frame.size.height ?? 0)-300))
} else if orientation == .RC || orientation == .CC {
label.text = "setupConstraints(.CC ou .RC \(superview?.frame.size.width)"
label.sizeToFit()
superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .trailing, relatedBy: .equal, toItem: superview, attribute: .trailing, multiplier: 1, constant: -50))
superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: superview, attribute: .top, multiplier: 1, constant: 50))
superview?.addConstraint( NSLayoutConstraint(item: self, attribute: .width, relatedBy: .equal, toItem: .none, attribute: .notAnAttribute, multiplier: 1, constant: (superview?.frame.size.width ?? 0)-100))
superview?.addConstraint(NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal, toItem: .none, attribute: .notAnAttribute, multiplier: 1, constant: (superview?.frame.size.height ?? 0)-100))
}
}
}
In the method layoutSubviews of my component, I called orientation which is an extension of UIView:
public var orientation: IosTraitClass {
if UIScreen.main.traitCollection.horizontalSizeClass == .regular &&
UIScreen.main.traitCollection.verticalSizeClass == .compact {
return .RC
} else if UIScreen.main.traitCollection.horizontalSizeClass == .compact &&
UIScreen.main.traitCollection.verticalSizeClass == .regular {
return .CR
} else if UIScreen.main.traitCollection.horizontalSizeClass == .compact &&
UIScreen.main.traitCollection.verticalSizeClass == .compact {
return .CC
} else if UIScreen.main.traitCollection.horizontalSizeClass == .regular &&
UIScreen.main.traitCollection.verticalSizeClass == .regular {
return .RR
} else {
return .none
}
}
Finally I made a UIViewController:
class ViewController: UIViewController {
@IBOutlet weak var container: MyCtrl!
override func viewDidLoad() {
super.viewDidLoad()
setupConstraints()
}
func setupConstraints() {
container.setupConstraints(view.orientation)
}
func calculatedConstraints() -> [NSLayoutConstraint] {
return [];
var constraints = [NSLayoutConstraint]()
container.removeConstraints(container.constraints)
if view.orientation == .CR {
//constraints.append(contentsOf: container.setSize(width: (view?.frame.size.width ?? 0)-60, height: (view?.frame.size.height ?? 0)-300))
} else {
//constraints.append(contentsOf: container.setSize(width: (view?.frame.size.width ?? 0)-40, height: (view?.frame.size.height ?? 0)-100))
}
return constraints
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
container.setupConstraints(view.orientation)
super.viewWillTransition(to: size, with: coordinator)
}
}
When I run my program the constraints are well applied in landscape or portrait mode.
But when I look in the interface Builder, constraints are not applied, and I don't understand
Why
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I test a very simple thing:
I have a Subclassed UIView as follow:
@IBDesignable
class myView: UIView {
override public init(frame: CGRect) {
super.init(frame: frame)
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override open func layoutSubviews() {
super.layoutSubviews()
layer.frame.size.height = 50
layer.borderWidth = 1
layer.borderColor = UIColor.green.cgColor
}
}
To install this component in Interface Builder, I add an UIView and I change the class name in the Inspector.
When I add the UIView, the height of this view is 128. I suppose it is a default value of IB. But I want this height to be 50.
When I change the name of the class in the IB inspector, the view is correctly drawn, white a height of 50, but when I select it, the size of the selection is the size of a default UIView
Is there a mean to correct this?
I develop an App in macos, and I need to access the documentDirectory:
let dialogURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
I get: file:///Users//Library/Containers/<devTeam.appName>/Data/Documents
But in the Library/Containers directory I don't have the <devTeam.appDirectory> (in my case "PR.medical") but (in my case "medical")
of course, it would be possible to hard code the name of the desired directory, but if in the future apple change anything, my app will not work properly.
Am I missing something?
I have an App for Iphone and Ipad.
in my UIViewController, the subviews installed depend of the different classes (CR, RC, CC, RR) because possible widths of the view are not the same.
This work very well on Iphone, because the width of the view is different, depending on the class (CR, RC, CC).
But for Ipad, the class is RR, no matter the orientation. Or in portrait and landscape, of course, width is not the same. In Interface Builder, I don't find a way to have subviews installed for Ipad in landscape and not in Portrait.
Is there a way to handle this, or do I have to handle this programatically?
For some programming reason, I need to know the real size (width and height) of an UIView wich has constraints.
Depending on the device I use, and depending on the orientation of the device, the width or height of my view change, but frame and layer frame don't give me the correct result.
Is there a mean to have the size?
I have an IOS application who uses coredata
As I want to develop and App extension which needs to share coredata with my app(Yes, I made a group App), I thought a good solution would be to create a framework with the, coredata model.
I did it, but after that the coredata of the main app is no longer necessary.
and I think I made a mistake when removing the file xcdatamodel from my app.
when I refer to an entity in the main application, it doesn't use the entity of the framework.
when I right click on an entity instance in my main application, I see a file which is: entity+CoreDataClass and of course I don't find it in the finder.
Did I made a mistake by simply remove the xcdatamodel from my App?
Do I have something to clean?
I'm complety lost with async await operation
I have a subclass of UITextField which provide a verif method
in the resignFirstResponder method, I call the verif Method and return true or false, depending of the result of the verif
the verif method is asynchrone, because it can make call to a web server.
My code is:
import UIKit
public enum VerifResult<S: NSString> {
case success
case failure(S)
}
@IBDesignable class TextField: UITextField {
@IBInspectable var obligatoire: Bool = false
override func resignFirstResponder() -> Bool {
var bRes = false
do {
let res = try await withCheckedThrowingContinuation {
continuation in
let result = try await verif()
continuation.resume(returning: result)
}
switch res {
case .success: bRes = true
case .failure(let msg): bRes = false
}
} catch {
return false
}
return bRes
}
public func verif() async throws -> VerifResult<NSString> {
if obligatoire && text == "" {
return .failure("Zone obligatoire")
} else {
// make call to a webserver and return .sucess or .failure
return .success
}
}
}
in the resignFirstResponder on the line try await, the compiler detects the error:
Invalid conversion from throwing function of type '(CheckedContinuation<_, Error>) async throws -> Void' to non-throwing function type '(CheckedContinuation<T, Error>) -> Void'
I'm lost, I don't understand why
where is my mistake?
I am very confused about UIScrollview auto layout
I want to make a very standard IOS Application with some textfields and textviews. When the keyboard appears, I want the current responder to be visible on screen.
It seems to me very simple, There ara many posts on the subject, but I don't obtain the correct result, and I think it comes from the layout of my scrollview and it's contentView.
For the layout, I do the following:
The left, top, right and bottom of my UIscrollView is pinned on the view of the UIViewController.
The left, top, right and bottom of the controlView is pinned on ContentLayoutGuide of the UIScrollview.
And, as I want the scroll to be only vertical, I have the width of the Content View to be equal to the width of the FrameLayoutGuide of the UIScrollView.
At this point, I have an error in interface Builder, which is: Scrollview needs constraint for Y position.
After that, in IB, I position constraints of all the fields in the contentView.
I still have the layout error in Interface Builder. Some posts say that the last subview in contentView as to be pinned to the bottom of the contentView. But I think it is not good, because it will give a height for the content view, or this height depends of the device to be used.
So I click on the error in Interface Builder, then on "Add missing constraints", and the new constraint pin the bottom of contentView to bottom of FrameLayoutGuide of the UIScrollView.
No error at this point, but if I run under simulator, I have the warning: "LayoutConstraints] Unable to simultaneously satisfy constraints."
No Matters, I go on
To eventually make the scroll when a UIControl becomes first responder, I write the following in my UIViewController:
`class BaseViewController: UIViewController {
// visibleRect is the part of the contentView which is visible on screen
var visibleRect: CGRect!
// scrollOrigin is the initial contentOffset of the scrollview
var scrollOrigin: CGPoint!
override func viewDidLoad() {
super.viewDidLoad()
registerKeyboardNotifications()
Let kbdGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard(_:)))
view.addGestureRecognizer(kbdGestureRecognizer)
}
func registerKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
}
@objc func dismissKeyboard(_ sender: UITapGestureRecognizer) {
view.endEditing(true)
if let scrollview = scrollview, let scrollOrigin = scrollOrigin {
scrollview.setContentOffset(scrollOrigin, animated: true)
}
}
@objc func adjustForKeyboard(notification: Notification) {
guard let keyboardValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }
let keyboardViewEndFrame = view.convert(keyboardValue.cgRectValue, from: view.window)
if let scrollview = scrollview {
visibleRect = scrollview.subviews[0].frame
} else {
visibleRect = view.frame
}
visibleRect.size.height -= keyboardViewEndFrame.size.height
}`
In adjustForKeyboard function, scrollview.subviews[0].frame as a negative y position.
All UIControls are subclassed so that in becomeFirstResponder, it calls the following function of UIViewController:
public func currentResponderChange(_ newResponder: UIResponder?) {
currentResponder = newResponder
if let scrollview = scrollview, let currentResponder = currentResponder as? UIView, currentResponder.isFirstResponder, let view = controllerView {
if scrollOrigin == nil {
scrollOrigin = scrollview.contentOffset
}
var frameConverted = view.convert(currentResponder.frame, from: view.window)
// si le scroll est uniquement vertical, on met x à zéro
frameConverted.origin.x = 0
if let scrollOffset = scrollOrigin {
frameConverted.origin.y -= scrollOffset.y
}
if visibleRect.contains(frameConverted) {
if let scrollOrigin = scrollOrigin {
scrollview.setContentOffset(scrollOrigin, animated: true)
}
} else {
var delta = (currentResponder.frame.origin.y+currentResponder.frame.size.height) - visibleRect.size.height //- scrollview.contentOffset.y
if let scrollOrigin = scrollOrigin {
delta -= scrollOrigin.y
}
scrollview.setContentOffset(CGPoint(x: 0, y: delta), animated: true)
}
}
}
It don't work, because of the visibleRect, which is not correct. And I think it comes from initial layout in Interface Builder. the view is effectively scrolled, but not for the correct amount
Can someone helps?
I have a framework named NetworkFramework which uses alamofire. Of course, somewhere in my sources, I have : import Alamofire
My framework has a podfile which contains:
target 'NetworkFramework' do
use_frameworks!
# Pods for NetworkFramework
pod 'Alamofire', '~> 5.5.0'
end
if I want to use this framework in an App I have 2 possibilities (if I don't mistake)
import NetworkFramework and his sources in the app
simply import NetworkFramework.framework
In the first case, all is compiled and there is no problem.
In the second case, when I try to compile the App, I got an error which is No such module Alamofire
I don't understand why.
Do I have to compile the App with the sources of the framework?
I see there is not many answers about quicklook posts
I have an IOS app which display items in a QLPreviewController and it works well when I presenty the QLPreviexwController.
Now I want to change the presentation: I want a ViewController with 2 viewContainer: One for informations about the object represented by quicklook, and the other with the previewController itself.
When I run the nw App, I don’t see the preview in the second viewContainer. The function numberOfPreviewItems is called, but previewItemAt is never called.
Do you think it is not possible to show a quicklook item in a viewContainer?
I develop an App which has a quicklook preview for files located on a web server
To realize this preview, I download the file and access it with a QLPreviewController
When I use simulator, I can see the downloaded files somewhere in library/developper/coresimulator..... and so on of my mac, and I can manually delete them. But if I search these files on the IPhone simulator, I can't find them.
What when I run the application on my real device? How will I be able to delete these files? because I think it take place in the IPhone
I develop a share extension for my app
the app compile and runs with no problem, but when I add a share extension to my App, without changing anything to the code of apple, I have error:
Unexpected input file: /Users/patricerapaport/Swift/Rangements/RangementsIOS/DEINIT_WARKING
and
unable to open dependencies file (/Users/patricerapaport/Swift/Rangements/RangementsIOS/Build/Intermediates.noindex/RangementsIOS.build/Debug-iphonesimulator/RangementsShareExt.build/Objects-normal/x86_64/RangementsShareExt-master-emit-module.d)
I precise that my App and my extension share the same group app
My version of Xcode is 14.1
I'm developping a hebrew custom keyboard (the way the wovels are handled in the apple hebrew keyboard is not satisfying for me).
As the hebrew language is from right to left, I expect that when I type a letter the cursor position moves to the left of the text, but it is not the case: it stays on the right, while new typed caharcters will be correctly positionned (on the left of the last character).
if I manually position the cursor on the left of the last character entered (using adjustTextPosition of textDocumentProxy) the next character whill not be on the left position, as expected but on the right position.
how can I fix the problem, and have the cursor on the left after typing a character?
I develop an app with a UITableView extracting data from a web server.
to spare communication between my app and my webserver, I calculate how many rows my tableView can display and I ask the web werver to send me a array containing this number of data.
when prefetching,rows, if the ;data corresponding to the indexPath is not in memory, I call the web server, otherwise I extract the data from memory.
everything works fine, but I notice that the amount of data grows at each call to the webserver, and is never released.
to release some data, I thought using tableview(cancelPrefetchingForRowsAt), but i'm not sure it is the good way to do it. I'm not sure that indexPathes calld in the cancelPrefetching method correspond to rows that UITableView doesn't use
I'm trying to make a custom TextField which eventually show errors when loosing focus
in a normal form, foreach TextField, I write:
TextField(label, text: $text)
.focused($checkoutInFocus, equals: <some Value>)
Text(textError)
.foregroundColor(.red)
.frame(height: textError == "" ? 0 : 20)
(I want to precise it's not all: I have many modifiers for the TextField and it becomes very difficult to read when there are many TextFields)
So I thought it would be a good idea to make a special view for each Textfield:
struct TextFieldWithError: View {
var label: String
@Binding var text: String
@Binding var textError: String
@FocusState.Binding var isFocused: Bool
init(label: String, text: Binding<String>, textError: Binding<String>, isFocused: FocusState<Bool>.Binding) {
self.label = label
self._text = text
self._textError = textError
self._isFocused = isFocused
}
var body: some View {
TextField(label, text: $text)
.modifier(TextFieldStyle())
.focused($isFocused)
Text(textError)
.foregroundColor(.red)
.frame(height: textError == "" ? 0 : 20)
}
}
My problem is that I don't find the way to act on the focusState.
In the mainView I write:
TextFieldWithError(label: "Email", text: $email, textError: $emailError, isFocused: checkoutInFocus == .<some Value>)
in place of the modifier
.focused($checkoutInFocus, equals: .email)
but the syntax is obviously not good: I get the error:
Cannot convert value of type 'Bool' to expected argument type 'FocusState.Binding'
Do you think there is a way?