My popover view controller dissapears when NSStatusBar IconView image changes - objective-c

I have a status bar app which shows a green circle in the status bar and alternates to a red circle every 10 seconds. It does this by using item.view = icon1; and item.view = icon2; to change the image. Initialised like this:
let item = NSStatusBar.systemStatusBar().statusItemWithLength(-1);
self.icon1 = IconView(imageName: "icon1", item: item);
self.icon2 = IconView(imageName: "icon2", item: item);
When you click on the green or red circle, a popover view with some settings I have made appears fine.
The problem is at each 10 second interval when the item.view changes to either the red or the green, the popover view closes and requires the user to click the green or red button again to show it.
How can I make the popover persist though status bar image changes and only disappear once the user clicks the red or green button again?
Here is my awakeFromNib() for the popover view:
override func awakeFromNib()
{
let edge = NSMinYEdge
let icon = self.icon
let icon2 = self.icon2
let icon3 = self.icon3
let rect = icon.frame
let rect2 = icon2.frame
let rect3 = icon3.frame
icon.onMouseDown = {
if (icon.isSelected)
{
self.popover?.showRelativeToRect(rect, ofView: icon, preferredEdge: edge);
return
}
self.popover?.close()
}
icon2.onMouseDown = {
if (icon2.isSelected)
{
self.popover?.showRelativeToRect(rect2, ofView: icon2, preferredEdge: edge);
return
}
self.popover?.close()
}
icon3.onMouseDown = {
if (icon3.isSelected)
{
self.popover?.showRelativeToRect(rect3, ofView: icon3, preferredEdge: edge);
return
}
self.popover?.close()
}
}
}

You have the popover attached to a view that is later removed from the view hierarchy. Instead of assigning a new view to NSStatusItem each time, use a single view and change it's properties to show different states (i.e. change it's image property).
Alternatively you can create an empty NSView and assign it to NSStatusItem view property. Then you can add and show your icons inside that view as needed. Make sure to attach the popover to this empty view instead of individual icons.

Put a breakpoint inside the popover class dealloc method to see the stack trace. You'll get a hint of why this is happening from that stack trace.

Related

RecyclerView custom LayoutManager remove unwanted views

I have a custom LayoutManager (inherited from LinearLayoutManager) that needs to calculate the item width of each child and remove all children from RecyclerView that has no space for them to appear.
Sample code (edited V2):
override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) {
super.onLayoutChildren(recycler, state)
// skip if orientation is vertical, for now we only horizontal custom menu
if (orientation == RecyclerView.VERTICAL) return
// skip if adapter has no items
if (itemCount == 0) return
var totalItemWidth = 0
var totalItemsCanFit = 0
// calculate menu item width and figure out how many items can fit in the screen
for (i in 0 until childCount) {
getChildAt(i)?.let { childView ->
totalItemWidth += getDecoratedMeasuredWidth(childView)
}
if (screenWidth > totalItemWidth) {
totalItemsCanFit++
}
}
// if all items can fit, do nothing and show the whole menu
if (childCount > totalItemsCanFit) {
// remove child views that have no space on screen
for (i in childCount - 1 downTo totalItemsCanFit) {
removeAndRecycleViewAt(i, recycler)
}
}
}
I have 2 questions:
Is the sample code above the correct way to approach this problem?
How can I add a 3-dot icon at the end after seeing that not all items could fit?
EDIT:
To clarify, what I am trying to achieve is a popup menu backed by a RecyclerView. The menu has no item limit, instead it should calculate each item width and remove all items that have no space. Also, add a 3-dot menu item as a more option at the end.
Regarding your first question:
See if addDisappearingView(View child) could help you,
according to the documentation:
To be called only during onLayoutChildren(Recycler, State) to add a
view to the layout that is known to be going away, either because it
has been removed or because it is actually not in the visible portion
of the container but is being laid out in order to inform RecyclerView
in how to animate the item out of view.
As for the second question - you simply need to implement a 'load more' feature to your recyclerView. How you'll implement this is up to your needs/design (if you want a button or auto-scroll...).
There are many tutorials for that, for example: https://androidride.com/android-recyclerview-load-more-on-scroll-example/ .

How to correctly navigate with navigation's stack in Xamarin.ios?

I'm currently working on a project in Xamarin.iOS and I don't have any idea how the stack system works.
I have a menu where I choose the language of my app and I would like to refresh on the fly the language on all the previous pages when I select a different language.
When I tap on the previous button in my language settings the previous page is not translated so I decided to create a new ViewController that I put on the top of the stack with this.NavigationController.PushViewController(new ViewController(), true)
but I don't think it's the best way to do it so I tried
this.NavigationController.PopToRootViewController(true) to have the root ViewController but is there a way to get just the previous page on the stack?
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
var cell = this.GetCell(tableView, indexPath);
cell.SelectionStyle = UITableViewCellSelectionStyle.None;
var previousIndexPath = NSIndexPath.FromRowSection(this.selectedIndex, 0);
this.selectedIndex = indexPath.Row;
var selectedLanguage = this.supportedCultures[this.selectedIndex];
Localization.Culture = selectedLanguage;
this.SaveLanguageToUserDefault(selectedLanguage);
this.TableView.ReloadRows(new NSIndexPath[] { previousIndexPath,indexPath }, UITableViewRowAnimation.None);
this.NavigationController.PopToRootViewController(true);
//this.NavigationController.PushViewController(new ViewController(), true);
}
In iOS if you are using a NavigationController and you want to Navigate to the previous ViewController you use the PopViewController Method in the NavigationProperty.
this.NavigationController.PopViewController(true);
This will make you app close the current page you are and will show the previous one.
Look that this is different to the PopToRootViewController.
Hope this helps.-
When you press back button ViewDidAppear medthod getting called in the coming page. Here you write your logic like after opening notification when going back setting count 0 etc
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
DashboardItem.NotificationCount = 0;
}

Disable scroll for PDFView inside NSCollectionView

I have a PdfView inside a CollectionView. Since both have its own scrollviews I have conflicts in scrolling. So i want to disable scrolling for PdfView. How can I do it?
My solution is a little rough, but does work.
I only wanted to stop horizontal scrolling on my PDFViews - my collection view scrolls horizontally.
I made a view that selectively filters out the scroll mouse events and put it over the PFD view.
class HorizontalScrollBlockerView: NSView
{
var scrollNextResponder: NSResponder?
override func scrollWheel(with event: NSEvent) {
guard scrollNextResponder != nil else {
return
}
if fabs(event.deltaX) >= fabs(event.deltaY) {
scrollNextResponder!.scrollWheel(with: event)
} else {
super.scrollWheel(with: event)
}
}
}
I set the view's 'scrollNextResponder' to be the superView of the PDFView.
I also wrote a method that gets the first child scroll view (enclosedScrollView) which makes sure the PDFView is solid in the horizontal axis when correctly scaled.
if let scrollView = pdfView.enclosedScrollView {
scrollView.usesPredominantAxisScrolling = true
scrollView.hasHorizontalScroller = false
scrollView.horizontalScrollElasticity = NSScrollView.Elasticity.none
}
For a regular Scroll View you can remove scrolls by setting horizontal & vertical scrolls to false value. So for a PDF view try this :
NSScrollView *enclosingScrollView = [myPdfView enclosingScrollView];
[enclosingScrollView setHasHorizontalScroller:NO];
[enclosingScrollView setHasVerticalScroller:NO];

ios 7 auto resize UINavigationController when In-Call status bar is toggle Monotouch

I'm having a problem when the in-call status bar it shows, I have tried.
navigationController = new UINavigationController ();
navigationController.NavigationBarHidden = true;
navigationController.View.AutosizesSubviews = true;
navigationController.View.AutoresizingMask = UIViewAutoresizing.FlexibleHeight|UIViewAutoresizing.FlexibleMargins|
UIViewAutoresizing.FlexibleTopMargin|UIViewAutoresizing.FlexibleBottomMargin;
navigationController.View.SizeToFit ();
window.RootViewController = navigationController;
window.RootViewController.View.AutosizesSubviews = true;
navigationController.View.AutoresizingMask = UIViewAutoresizing.FlexibleHeight|UIViewAutoresizing.FlexibleMargins|
UIViewAutoresizing.FlexibleTopMargin|UIViewAutoresizing.FlexibleBottomMargin;
but is still pushing bottom all views, hiding all buttons or controls at the bottom of the view, I also tried the same code in the Root View controller and doesn't work.
I'm using flexible UI for all controls this way:
btnContacts = IOTM.GUI.CreateButton ("MainMenu/btncontacts.png", 0f,Frame.Height - (Frame.Height * 0.225f), Frame.Width, (Frame.Height * 0.075f));
and I'm also hiding Navigation Bar
Can someone help me?
There is another way to auto resize view or detect changes in status bar to reload my views?

How to toggle visibility of NSSplitView subView + hide Pane Splitter divider?

We have a parent Split view (NSSplitView), and two subviews, Content and SideBar (the sidebar is on the right).
What would be the optimal Cocoa-friendly way to toggle the SideBar view?
I would really love it, if the suggested solution includes animation
I really don't need any suggestions related to external plugins, etc (e.g. BWToolkit)
HINT : I've been trying to do that, but still I had issues hiding the divider of the NSSplitView as well. How could I do it, while hiding it at the same time?
Here's a pretty decent tutorial that shows how to do this: Unraveling the Mysteries of NSSplitView.
Hiding the divider is done in NSSplitView's delegate method splitView:shouldHideDividerAtIndex:.
You will have to animate the frame size change yourself if you don't like the way NSSplitView does it.
Easiest way to do it is as follows - and it's animated: [SWIFT 5]
splitViewItems[1].animator().isCollapsed = true // Show side pane
splitViewItems[1].animator().isCollapsed = false // hide side pane
I wrote a Swift version of the content in the link from #Nathan's answer that works for me. In the context of my example splitView is set elsewhere, probably as an instance property on an encompassing class:
func toggleSidebar () {
if splitView.isSubviewCollapsed(splitView.subviews[1] as NSView) {
openSidebar()
} else {
closeSidebar()
}
}
func closeSidebar () {
let mainView = splitView.subviews[0] as NSView
let sidepanel = splitView.subviews[1] as NSView
sidepanel.hidden = true
let viewFrame = splitView.frame
mainView.frame.size = NSMakeSize(viewFrame.size.width, viewFrame.size.height)
splitView.display()
}
func openSidebar () {
let sidepanel = splitView.subviews[1] as NSView
sidepanel.hidden = false
let viewFrame = splitView.frame
sidepanel.frame.size = NSMakeSize(viewFrame.size.width, 200)
splitView.display()
}
These functions will probably methods in a class, they are for me. If your splitView can be nil you obviously have to check for that. This also assumes you have two subviews and the one at index 1, here as sidePanel is the one you want to collapse.
In Xcode 9.0 with Storyboards open Application Scene select View->Menu->Show sidebar. CTRL-click Show Sidebar, in sent actions delete the provided one, click on x. From the circle CTRL drag to First Responder in application scene and select toggleSideBar to connect to. Open storyboard and select the first split view item and in attributes inspector change behaviour from default to sidebar. Run and try with view menu item show/hide. All done in interface builder no code. toggleSideBar handles the first split view item. https://github.com/Dis3buted/SplitViewController
I got some artifacts with the code above, likely because it was out of context. I am sure it works where it was meant to. Anyway, here is a very streamlined implementation:
// this is the declaration of a left vertical subview of
// 'splitViewController', which is the name of the split view's outlet
var leftView: NSView {
return self.splitViewController.subviews[0] as NSView
}
// here is the action of a button that toggles the left vertical subview
// the left subview is always restored to 100 pixels here
#IBAction func someButton(sender: AnyObject) {
if splitViewController.isSubviewCollapsed(leftView) {
splitViewController.setPosition(100, ofDividerAtIndex: 0)
leftView.hidden = false
} else {
splitViewController.setPosition(0, ofDividerAtIndex: 0)
leftView.hidden = true
}
}
To see a good example using animations, control-click to download this file.
If your NSSplitView control is part of a NSSplitViewController object, then you can simply use this:
splitViewController.toggleSidebar(nil)