NSOutlineView Selected Text Color Not Working in Swift - nsoutlineview

Swift 4, macOS 10.13
I have an NSOutlineView and I'm trying to customize the look of each row when the user clicks it.
I have a view-based NSTableCellView subclass that I'm using for the cell. When I override backgroundStyle, the icon change works perfectly. But the text color is doing something weird.
Here's a video to demonstrate: http://d.pr/v/suTD8B
Here's my code:
class MenuItemCell: NSTableCellView{
#IBOutlet weak var label: NSTextField!
#IBOutlet weak var icon: NSImageView!
//Customizes the selected state of menu row
override var backgroundStyle: NSView.BackgroundStyle {
set{
if let rowView = self.superview as? NSTableRowView {
super.backgroundStyle = rowView.isSelected ? .dark : .light
}
if self.backgroundStyle == .dark {
label.textColor = NSColor.white
icon.image = NSImage(named: NSImage.Name(rawValue: "menu-project-selected"))
}else{
label.textColor = NSColor.menuTextColor
icon.image = NSImage(named: NSImage.Name(rawValue: "menu-project"))
}
}
get{ return super.backgroundStyle }
}
}
Any idea what's wrong? I've been searching for hours and can't figure it out.

It turns out that this would never work reliably while the NSOutlineView Highlight was set to Source List in the storyboard editor. It was really unreliable.
Once I changed it to Regular then it worked fine.

Related

How can i pass Label from viewController to another one without using segue?

Hi im new in swift and im trying to build a store application, i already build it but i have a problem with only one thing which is , i want to pass the data ( label, image, price label ) to another viewController without using segue. I tried all the method ( delegate, notificationCenter, closure ) but i didn't solve it.
this is a picture for new project i create it to explain what i want to do exactly .
i hope i get the solution because i search alot for it maybe for months but i didn't solve my problem :(
this is my code
passingViewController
import UIKit
extension passingDataViewController : textDelegate {
func sendText(withText: String) {
Label.text = withText
}
}
class receivingDataViewController: UIViewController {
#IBOutlet var label2: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
receivingDataViewController
import UIKit
extension passingDataViewController : textDelegate {
func sendText(withText: String) {
Label.text = withText
}
}
class receivingDataViewController: UIViewController {
#IBOutlet var label2: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
You didn't explain how you're creating the new controllers, but here's a simple example that just uses a tab controller. This makes use of a shared singleton to pass around the delegate, but if you're creating each controller programatically, you could update the delegate when you create each new instance.
For this example, I have created a singleton that contains the delegate
import Foundation
class SharedSingleton : NSObject
{
var updateDelegate : UpdateDelegate?
static let sharedInstance = SharedSingleton()
}
And then we define the protocol you're using.
In the passing view, you can define it like this
protocol UpdateDelegate
{
func updateDisplay(text : String)
}
and you use it (in the passing view like this
var sharedInstance = SharedSingleton.sharedInstance
#IBAction func cmdGo(_ sender: Any) {
sharedInstance.updateDelegate!.updateDisplay(text: txtInput.text!)
}
You define the receiving view to use the update protocol
class ReceivingViewController: UIViewController, UpdateDelegate {
and set up the delegate
var sharedInstance = SharedSingleton.sharedInstance
override func viewDidLoad() {
super.viewDidLoad()
// setup the delegate through the shared instance
sharedInstance.updateDelegate = self
}
and then implement the update method
func updateDisplay(text: String) {
lblDisplay.text = text
}
That's it. You may need to update your implementation to change how you share the delegate pointer, but that's the process.

Extract the background colour of a UIImageview in an array

I want to determine the background colour of an imageview when it is tapped and perform an action based on the colour. I cannot fathom the syntax for getting the information from the array in which the imageviews are stored. I have tried the below but it says the stated error. Any help would be appreciated. I am new and I'm sorry if I'm wasting peoples time, I'm learning by making my own app and its throwing up a lot of questions. Kind regards.
'Value of type [UIImageView] has no member backgroundColour.
#IBAction func onTapping() {
if squares.backgroundColor == UIColor.red {
// code
}
}
First you need to set userIteractionEnable on all your UIImageViews
Next change your method signature to:
#IBAction func onTapping(_ sender: UITapGestureRecognizer) {
Then you will need to know which image view you are tapping on by checking the sender view property:
#IBAction func onTapping(_ sender: UITapGestureRecognizer) {
let systemRed = UIView()
systemRed.backgroundColor = .systemRed
if sender.view?.backgroundColor == systemRed.backgroundColor {
print("systemRed")
} else {
print("systemYellow")
}
}

iOS13.1 UIAlertController with preferedStyle: .actionSheet cannot change title's text color and font

I change title font and color like this:
let titleAttributes = [NSAttributedStringKey.font: UIFont(name: "HelveticaNeue-Bold", size: 25)!, NSAttributedStringKey.foregroundColor: UIColor.purple]
alert.setValue(titleString, forKey: "attributedTitle")
Before iOS13 this worked fine both for preferredStyle .alert and .actionSheet.
Now it only works for .alert and doesn't work for .actionSheet.
Someone please any help?
iOS 13 now embeds the UIAlertController title in a UIVisualEffectView, and only the title's alpha channel affects its appearance. If it is critical to control the exact color, I think you could try finding the subview class _UIInterfaceActionGroupHeaderScrollView, remove its child UIVisualEffectView, and then add your own UILabel back in. But no guarantees it will work or that it won't trigger a crash. You can use the allSubviews extension below and compare each to this:
let grpHeader = NSClassFromString("_UIInterfaceActionGroupHeaderScrollView")
Or if you just need to ensure that your title is visible based on your app's color scheme I had success with the following, which should be quite safe to use at least until iOS 14 is released.
let alertController = UIAlertController(....)
for subView in UIView.allSubviews(of: alertController.view) {
if let effectView = subView as? UIVisualEffectView {
if effectView.effect is UIVibrancyEffect {
if #available(iOS 13.0, *) {
// iOS 13.1 default blur style is UIBlurEffectStyleSystemVibrantBackgroundRegular which is NOT currently defined anywhere
// if your alert controller color is dark, set to .systemMaterialDark
// if your alert controller color is light, set to .systemMaterialLight
effectView.effect = UIVibrancyEffect(blurEffect: UIBlurEffect(style: UIBlurEffect.Style.systemMaterialDark), style: .secondaryLabel)
}
break
}
}
}
// You will need this UIView category to get an array of all subviews,
// as the view heirarchy is complex. In iOS13 it is:
// UIAlertController.UIView ->
// _UIAlertControllerInterfaceActionGroupView ->
// UIView
// _UIInterfaceActionGroupHeaderScrollView
// ** UIVisualEffectView **
// _UIInterfaceActionRepresentationsSequenceView
// _UIDimmingKnockoutBackdropView ]
// ** all your button actions **
extension UIView {
class func allSubviews<T : UIView>(of view: UIView) -> [T] {
var subviews = [T]()
for subview in view.subviews {
subviews += allSubviews(of: subview) as [T]
if let subview = subview as? T {
subviews.append(subview)
}
}
return subviews
}
}

ARKit – Add a "SCNNode" to an "ARAnchor"

I'm not sure I am approaching this correctly. I have a long rectangular box that I want to add -1.5 from the camera when the app starts up. But I want it to be stationary, like the ship that comes default in an ARKit project. But whenever I add it, the object stays relative (distance wise) to the camera. i.e - move towards it, it moves back, move back, it moves forward.
I though dropping an anchor on the scene would resolve this but I am still getting the same affect. Here is my code. Any help would be appreciated:
override func viewDidLoad() {
super.viewDidLoad()
// Set the view's delegate
sceneView.delegate = self
// Show statistics such as fps and timing information
//sceneView.showsStatistics = true
// Create a new scene
let scene = SCNScene()//
// Set the scene to the view
sceneView.scene = scene
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
//configuration.planeDetection = .horizontal
// Run the view's session
sceneView.session.run(configuration)
print(#function, sceneView.session.currentFrame)
}
// MARK: - SCNSceneRendererDelegate
func renderer(_ renderer: SCNSceneRenderer, didRenderScene scene: SCNScene, atTime time: TimeInterval) {
print(#function, sceneView.session.currentFrame)
if !hasPortalAnchor {
//add anchor - this may take a second as the current frames are initially nil
if let currentFrame = sceneView.session.currentFrame {
var translation = matrix_identity_float4x4
translation.columns.3.z = -1.3
let transform = simd_mul(currentFrame.camera.transform, translation)
if (arrAnchors.count < 1) {
let portalAnchor = ARAnchor(transform: transform)
sceneView.session.add(anchor: portalAnchor)
arrAnchors.append(portalAnchor)
print(arrAnchors)
}
}
} else {
hasPortalAnchor = true
}
}
//this function gets called whenever we add an anchor to our scene
func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
let portalScene = SCNScene(named: "art.scnassets/portal.scn")!
return portalScene.rootNode.childNode(withName: "portal", recursively: true)
}
Are you deliberately using the renderer(_:) function? If not then you can just use the following viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
sceneView.delegate = self
let scene = SCNScene(named: "art.scnassets/portal.scn")!
sceneView.scene = scene
}
This will replace the default rocket that appears on startup, with your portal scene. (Note that the scene may move around if tracking hasn't been established. For instance if the light is low, or if you are in an environment without many features (a blank or repetitive wall for instance)).
Also it looks like you're not actually setting hasPortalAnchor to true? Is it being set somewhere else?

UIPageViewController disable scrolling

I am using a UIPageViewController with transitionStyle UIPageViewControllerTransitionStyleScroll and navigationOrientation UIPageViewControllerNavigationOrientationVertical
I also have a UIPanGestureRecognizer on the view and I want to disable page scrolling when the pan gesture is active.
I am trying to set the following when the gesture begins:
pageViewController.view.userInteractionEnabled = NO;
This seems to have no effect, or it appears to work sporadically.
The only other way I have found to do it (which works) is to set the UIPageViewController dataSource to nil while the pan gesture is running, however this causes a huge delay when resetting the dataSource.
UIPageViewController uses some UIScrollView object to handle scrolling (at least for transitionStyle UIPageViewControllerTransitionStyleScroll). You can iterate by controller's subviews pageViewController.view.subviews to get it. Now, you can easly enable/disable scrolling:
- (void)setScrollEnabled:(BOOL)enabled forPageViewController:(UIPageViewController*)pageViewController
{
for (UIView *view in pageViewController.view.subviews) {
if ([view isKindOfClass:UIScrollView.class]) {
UIScrollView *scrollView = (UIScrollView *)view;
[scrollView setScrollEnabled:enabled];
return;
}
}
}
For those who are using swift instead of objective-c, here is Squikend's solution transposed.
func findScrollView(#enabled : Bool) {
for view in self.view.subviews {
if view is UIScrollView {
let scrollView = view as UIScrollView
scrollView.scrollEnabled = enabled;
} else {
println("UIScrollView does not exist on this View")
}
}
}
Everyone is complicating this very very much.
This is the whole function you need to disable or enable the scroll.
func enableScroll(_ enable: Bool) {
dataSource = enable ? self : nil
}
Swift 4.2 Version of the answer
func findScrollView(enabled: Bool) {
for view in self.view.subviews {
if view is UIScrollView {
let scrollView = view as! UIScrollView
scrollView.isScrollEnabled = enabled
} else {
print("UIScrollView does not exist on this View")
}
}
}
then yourpagecontorller.findScrollView(enabled: false)
You may also disable gesture recognizers.
for (UIGestureRecognizer *recognizer in pageViewController.gestureRecognizers)
{
recognizer.enabled = NO;
}
Unlike the popular answer, which relies on existing of the inner UIScrollView, this one uses public gestureRecognizers array. The underlying scroll view may not exist if you use book-style paging.

Resources