I've written a custom class based on UIPickerView. Within a class I implemented next method:
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
let min = (selectedRow(inComponent: 0) % minutes.count)
let sec = (selectedRow(inComponent: 1) % seconds.count)
self.min = min
self.sec = sec
}
Every time user has selected value from "min" and "sec" using picker view, these class variables are changed accordingly. So, it's work ok.
Now, I would like this class to send event every time these variables are changed. Is it possible to adopt valueChanged event for this class, and how to implement it, or I have to make custom event for these purposes? I would like to do it in that way to be able making action outlets via IB. Please, correct me if I missed the pattern.
May be I put this question in other words: what makes the build-in UIDataPicker able to connect to view controller within interface builder with actions outlets - and what should I add to my custom class to achieve partially that functionality?
Apple stated that: "UIDatePicker class uses a custom subclass of UIPickerView to display dates and times." Correct me here if I'm wrong, but they also point out that UIDatePicker inherits from UIControl rather than from UIPickerView. As for UIPickerView - they say it inherits from the UIView. So, I see no connection in terms of inheritance of UIControl for UIPickerView and UIDatePicker. Also I can't inherit UIControl to obtain event sending functionality due to multiple inheritance of UIView class. Can't understand why things here so weird and I can't use UIControl functionality for UIPickerView.
create YourCustomControl inherit from UIControl
addSubview UIPickerView
set YourCustomControl as a delegate for this picker
To send event you need add this line
sendActions(for: .valueChanged)
in every place where these variables are changed
UIKit - sendActions
Related
What are the downsides to not following this process?
let parent = UIViewController()
let child = UIViewController()
parent.view.addSubview(child.view)
parent.addChild(child)
child.didMove(toParent: parent)
// and to remove
child.willMove(toParent: nil)
child.removeFromParent()
child.view.removeFromSuperview()
and instead just doing something more on the order of
let parent = UIViewController()
let child = UIViewController()
parent.view.addSubview(child.view)
// and to remove
child.view.removeFromSuperview()
My specific desire is to use SwiftUI views in place of UIViews sprinkled through my project, but officially you're supposed to use a UIHostingController and embed it as a child view controller of whatever parent view controller it belongs to.
I was previously under the impression that you have to call these methods, but then another developer suggested I just try not calling them with the assumption I'm only missing out on view controller lifecycle events (which I don't think matter to me in most cases). I've since tried it and it worked, but I'm worried about what I'm missing/why this might be a bad idea.
I recently came across an example of something you might lose if you don't add the UIHostingViewContoller as a child of the parent view controller in this article about using SwiftUI views in self-sizing table view cells. If you don't add it as a child, the height of the cell holding its view is not always calculated correctly.
https://noahgilmore.com/blog/swiftui-self-sizing-cells/#view-controller-containment
Is there any way to change the selection color of a sidebar item?
For example the default color of macOS 10.14.x dark theme is blue, would it be possible to change this color?
I took a look here: Cocoa osx NSTableview change row highlight color
but I had difficulty translating to Applescript, thanks in advance.
Without a sample or MCVE project it is going to be tricky providing a drop-in solution. The topics and answers you linked to are overriding the NSTableView or NSTableRowView classes, so I can give you a generic solution for that. Subclassing in AppleScriptObjC can be a bit of a pain, depending on what you need to reference, but is fairly straightforward. Essentially you are putting a custom class in between the regular class and your application, where you can intercept the various standard method calls.
For a cell-based table view example, add a new empty file to your project by using the File > New > File... menu item. The name of the _file _isn't important (e.g. TableViewHighlight.applescript or whatever), the name of the script is what will be used by Xcode. Here I am using MyTableView for the class name and referencing a tableView outlet property from the AppDelegate:
script MyTableView -- the name of your custom class
property parent : class "NSTableView" -- the parent class to override
property tableView : a reference to current application's NSApp's delegate's tableView
property highlightColor : a reference to current application's NSColor's greenColor -- whatever
# set the row highlight color
on drawRow:row clipRect:clipRect
if tableView's selectedRowIndexes's containsIndex:row then -- filter as desired
highlightColor's setFill()
current application's NSRectFill(tableView's rectOfRow:row)
end if
continue drawRow:row clipRect:clipRect -- super
end drawRow:clipRect:
# set the highlight color of stuff behind the row (grid lines, etc)
on drawBackgroundInClipRect:clipRect
highlightColor's setFill()
current application's NSRectFill(clipRect)
continue drawBackgroundInClipRect:clipRect -- super
end drawBackgroundInClipRect:
end script
In the Interface Editor, use the Identity Inspector to set the class of your table view to the MyTableView class. Finally, in your table view setup set its highlighting to none, since it will be done by your subclass (again, assuming a tableView outlet is connected to the table view):
tableView's setSelectionHighlightStyle: current application's NSTableViewSelectionHighlightStyleNone
For a view-based table view example, the process is similar, but NSTableRowView is the one to subclass. Here the name of the script/class I am using will be MyTableRowView:
script MyTableRowView -- the name of your custom class
property parent : class "NSTableRowView" -- the parent class to override
property highlightColor : a reference to current application's NSColor's redColor -- whatever
# draw the selected row
on drawSelectionInRect:dirtyRect
continue drawSelectionInRect:dirtyRect
highlightColor's setFill()
current application's NSRectFill(dirtyRect)
end drawSelectionInRect:
end script
In the Interface Editor, set the table view's highlight to regular using the Attributes Inspector, and add a tableView:rowViewForRow: method to the table view's delegate:
on tableView:tableView rowViewForRow:row
set rowIdentifier to "MyTableRow"
set myRowView to tableView's makeViewWithIdentifier:rowIdentifier owner:me
if myRowView is missing value then
set myRowView to current application's MyTableRowView's alloc's initWithFrame:current application's NSZeroRect
myRowView's setIdentifier:rowIdentifier
end if
return myRowView
end tableView:rowViewForRow:
There are other options, of course, but that should get you started, and help with translating some of those Objective-C answers/examples.
I have a TabView and I want to do animated switching between pages, like this:
https://stackoverflow.com/a/54774397/5376525
Is it possible for SwiftUI?
I actually just implemented this using SwiftUI. Here's what I did:
1) Create a SwiftUI view that conforms to UIViewControllerRepresentable. I used the init method to provide it an array of SwiftUI views of type AnyView. There is some work to do in the makeUIViewController and the updateUIViewController methods so we'll come back to that.
I created a typealias to pass a tuple of Views, their Image Name (assuming you're using system images) and the View name. It looks like this:
typealias TabBarItemView = (ViewName: String, ImageName: String, TargetView: AnyView)
2) You'll need to create a class that conforms to the UITabBarControllerDelegate. Within that delegate, you can override the tabBarController(_ tabBarController: UITabBarController, animationControllerForTransitionFrom fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning method.
Part of this requires you to create another class, one that conforms to UIViewControllerAnimatedTransitioning. This class requires you to implement two functions: transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval which just needs you to specify how long you want the animation to last.
The second function is animateTransition(using transitionContext: UIViewControllerContextTransitioning) which requires you to do some heavier lifting. Within this function, you'll need to design the animation that moves the views. Essentially, you should be applying a CGAffineTransform that moves the view from off screen (imagine a stage to the left or right of the screen) onto the screen while moving the other view in the same direction off-screen. At the end of the function, you can animate your transforms using something like:
UIView.animate(withDuration: animationDuration, animations: moveViewsClosure, completion: cleanUpClosure)
where animationDuration specifies how long this will take, moveViewsClosure is applying the transforms, and cleanUpClosure is actually replacing the views with one-another.
Once you have the class conforming to UIViewControllerAnimatedTransitioning you should be able to return it as the output of the UIViewControllerAnimatedTransitioning function.
3) Now that you have your delegate and animation classes created, you can assign the delegate to a UITabViewController within the SwiftUI view we started in. At the top of the struct, I created a variable of type UITabViewController and used the default initializer. Within the init function, you should set the delegate to an instance of the delegate class we created above.
4) Now we can implement the makeUIViewController and the updateUIViewController functions. Within makeUIViewController you'll need to load the array of views using the UIHostingController to enable your SwiftUI views to sit in the UIKit view controller. Once you have all your views loaded, you can return the UITabViewController from the top. Within the updateUIViewController, you will likely need to reset the delegate to the view controller. Because SwiftUI is using structs, it is not uncommon for your view to get recreated as it is updated; I have found it will lose the reference to the delegate as a result and this was how I solved it.
I realize I could have provided all of my code, but it's fairly lengthy and I think you'll have an easier time troubleshooting it if you understand the process.
I'm trying to figure out the best (cleanest) way to structure some code in C++ for an application I'm building. I think MVC makes sense as the way to go, but after a fair amount of research I'm not totally clear I'm doing things the right way.
Here's an example to illustrate my question:
Model
I have a class which contains drawing data called Canvas. An example function, used to clear the current contents of the canvas, is ClearCanvas().
Ultimately, I want a button in the interface to be able to call this function and clear the canvas.
Controller
I have a controller class for the canvas: CanvasController
The controller creates and then holds a reference to a canvas object: CurrentCanvas
The controller also creates the view: CanvasView and then sets a reference to itself on the view: CurrentCanvasView->SetControllerRef(this);
View
The view is made up of a series of nested classes that define the UI. For example, the hierarchy leading to the button in question might be something like this:
CanvasView
-VerticalBox
--HorizontalBox
---Button
During the view's constructor, a reference to the controller is passed from the view to all interactive elements, eg. NewButton->SetControllerRef(this->GetControllerRef());
Button Pressed
So now when the button is pressed, it can function like this:
void ClearCanvasButton::OnButtonPressed()
{
Controller->CurrentCanvas->ClearCanvas();
}
So my general question is: (1) does this seem like the right way to be doing things, or badly structured?
Also (2): Should the controller be encapsulating the canvas functions, for example:
void CanvasController::ClearCanvas()
{
CurrentCanvas->ClearCanvas();
}
Such that the function on the button could simply be:
void ClearCanvasButton::OnButtonPressed()
{
Controller->ClearCanvas();
}
I'm just not sure whether it's correct to essentially be passing down a reference to the controller to all elements of the view which ultimately want to change the model, or whether there is a cleaner way.
Apologies if the question has been asked a thousand times in a thousand different ways, I have been searching around trying to understand this.
You don't need a class ClearCanvasButton, if your Button class contains a member like
std::function<void()> onButtonPressed;
or similar, rather than
virtual void onButtonPressed() {};
You then pass a lambda that references the controller
CanvasView::CanvasView()
{
// make the widgets
Button.onButtonPressed = [Controller](){ Controller->ClearCanvas(); };
}
I would like to change the text of my UIBarButtonItem from another class (objective-C++) that I use in my project.
I have an IBOutlet myButton setup in myViewController and I can successfully do something like:
[ myButton setTitle:#"newTitle" ];
in myViewController.mm
Now I would like to do the same but from myCppClass that I use in my project.
Is there a way for myCppClass to access myViewController's myButton?
Shall I use some type of delegation mechanism?
I am pretty new to Ios and objective-C.
Thanks,
Baba
Create a method within your myViewController class to change the button title, then call that method from myCppClass by following the instructions described in this answer:
How to call method from one class in another (iOS)
https://stackoverflow.com/a/9731162/2274694
The short answer is, don't. You should treat a view controller's views as private. Instead, add a method to your VC like changeButtonTitle. Then call that method from from your other class.
The answers above are correct, but from your comments I suspect you aren't yet happy.
If you are super lazy, and you don't mind the string being the same in all instances of the VC (which in practice is usually the case) you could simply write a getter and setter for the string name as a class variable in the destination class. That way you don't even need access to the actual instance of the class, just its name. Tacky but super easy.
As others have pointed out, don't try and modify the buttons on a different VC directly. Pass a message and have the owning VC do it when it loads.
Well, passing messages forwards (to a new VC) is very easy. At the bottom of every VC class code there is #pragma navigation section commented out which gives you a handle to the destination VC. Cast it to the proper type and you set properties in the destination VC instance. In your case, create a public property NSString which holds the button text in your destination VC, and set it in your navigation section. This could be any class, or even a delegate, but a simple string should work.
Passing messages backwards (to previous VCs) can work the same way but it starts to get messy. You can programatically step back through the stack of VCs to find a particular (instance of) a VC. One of the answers to Get to UIViewController from UIView? gives sample code for stepping back through view controllers.
But if its simply forward communication, passing messages or information through
(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
at the bottom of the VC code and the commented out lines below is very easy and safe.