Interchange Children between two Layout<View> - xamarin

I am developing in Xamarin for iOS, Android and UWP. I created a custom control called DragAndSwapContainer which implements two custom behaviors: DragBehavior and DropBehavior.
DragBehavior basically adds a PanGestureRecognizer to the View and emits an event when the View is being 'dragged' (and also translates the view according to the Pan done by the user). On the other side, DropBehavior listens to this events and emits other events when a View is passing over the container or when a View is dropped inside.
DragAndSwapContainer acts as a container that can receive other views, and as a draggable and droppable view at the same time. The goal of this container is to enable the user to swap between two views by dragging and dropping one into the other one.
When a View is dropped inside this Container what I do is, basically, to swap the Children Views that both containers have (the one with the view that was dragged, and the one receiving the dropped view).
Here's a piece of code for the DragAndSwapContainer (which inherits from Grid):
private void OnViewDroppedInside(object sender, DroppedEventArgs e)
{
var draggedViewContainer = e.DroppedView.Parent as DragAndSwapContainer;
draggedViewContainer.Children.Add(this.Children.First());
this.Children.Add(e.DroppedView);
}
Since each View can have only one parent, this works fine: Child View is exchanged by the DragAndSwapContainers.
Everything works fine as respects to iOS and Windows, but I am facing some problems with Android.
I am getting the following error https://github.com/xamarin/Xamarin.Forms/pull/8888 when swapping two views. After some debugging I conclude that the problem arises because while swapping children (in between the two lines of code of Children.Add) Android native renderers are disposed, so I lose track of the View.
Also it is something that doesn't happen always, seems that there's some timings issues. If I attach my Analytics service (which reports to a cloud server and adds some overhead) the issue happens way more often.
The error mentioned seems to be fixed in the Xamarin.Forms version I have (since it was merged already in v4.4.0) but I'm still having the exact same error call stacks.
Given this situation, is there another better way to exchange children between two Layout?

Related

drag and drop between different recyclerviews with animation

I'm creating a simple (or so I thought) app that allows a user to drag/drop/reorder items within one of two recyclerview lists, or from one list to another. It should animate as you are dragging items, opening gaps that help you easily drop the item into the target spot. This functionality needs to go both ways between the lists. And for extra fun, drag should start on touch, not long press.
In case it makes any difference I'm trying to stick to MVVM, and my 2 recyclerviews are in 2 different fragments, but combined in one screen for this activity.
I'm a relative newbie to android, and using kotlin.
What I have managed so far
I can achieve a nice animation within one recyclerview, using ItemTouchHelper.
OR
I can achieve drag and drop from one recyclerview to the other, and I can start that on touch rather than long press, using View.OnDragListener.
What I can't seem to do is get both of those working at once--drag to another view, but with those beautiful animations ItemTouchHelper provides as the drag is underway.
I have tested all kinds of combinations of attaching customized drag or touchlisteners to my viewholders or recyclerviews. The closest I've gotten to getting things working is attaching the draglistener to the recyclerviews only, in order to receive the dropped view. Then I have set draglisteners and touchhelpers on the viewholders (via the recyclerview adapter).
With this setup I can drag between or within recyclerviews on touch, and have managed to get an animation AFTER drop by calling onItemMove of my adapter (provided as a parameter in my custom draglistener) from within the ACTION_DROP of my dragListener.
I've been working on this for a VERY LONG TIME and googled the heck out of it without luck. Help deeply appreciated.

How to reuse single ViewController/"Screen-Layout" in Swift3 / Xcode

What would be the specific steps and code (aka, the simplest possible example) - as per best practices in Swift/Xcode - for developing a dynamic UI with the following "Hello World" implementation requirements?
Create a single view controller with a specific layout - let's say just 2 labels (First Name and State), and 2 buttons (Back and Next)
Be able to then reuse that layout as many times as necessary for a new/subsequent screen, that user can navigate to from where the user is currently at, and where the same layout components (Name and State) are updated with the content for the specific screen (in the sequence) that will be shown
Here's a screen shot of what that could like if the screens are hardcoded in the StoryBoard, where the next buttons are connected with Show Segues:
I am new to Swift/Xcode, coming from a background in Android development. Studying Swift, I have not so far run across much tutorials to implement this kind of UI/UX via a dynamic approach with a reusable layout definition. The tutorials I'm seeing seem to all require that every screen that is necessary, be explicitly added via the IDE StoryBoard
For a concrete/specific example of what I'm looking for, in Android the common way to solve for this is :
Create a Java class that extends Fragment, and a corresponding layout that has the 2 text labels and 2 buttons
For the fragment - define a constructor that takes 2 parameters: Name, State
Every time a new screen is needed, a new instance is generated where the contructor is called with the necessary Name and State parameters for the new view
The new instance is pushed onto the fragment manager instance, and that causes the new screen to load for the user
When user clicks Next (where next is possible), steps 3-4 are repeated for the new content
Use UINavigationController and hide navigation bar.
advantage: navigationcontroller could help you 'next' and 'back' view controllers easily.
it's a good way for your achieve.
Use ContainerView.
it's more like fragment in android.
Use uiview only.
it's simple and easily.

Can receive pointerDragged but not pointerPressed in a container

I have a UI in Codenameone where a container contains another container which contains some widgets. On the bottom level container I'm able to receive pointerDragged events but not pointerPressed. These (pointerPressed) seem to be consumed by the widgets on the top of the hierarchy, but not move down to the bottom container.
How can I fix this?
I'd like to do this to detect left-right swipes on the bottom container. Is there perhaps a better way to do that?
Only focusable components receive the events directly in Codename One otherwise we would have to deliver events to multiple components which might inhibit performance.
The best way to do this is to use an existing component, e.g. Tabs supports swiping and hiding the tabs so you can just use that.
Making the Container focusable is probably not as desireable (although possible) since it might make interaction with the components within difficult.
You can use a pointer listener on the parent form as the Tabs component does internally. This should always work since the form gets all the events: https://github.com/codenameone/CodenameOne/

Why might an NSTableView redraw every cell on scroll?

I have an NSTableView with 5 columns, each containing a stock NSTableCellView in the nib. (The stock cells have a text box and an optional image.) When populated, the table has around 50 rows. Everything displays fine, but scrolling performance is pretty bad. It looks like this is happening because every cell gets a drawRect: message for its full rect whenever the table scrolls. However, neither reloadData nor reloadDataForRowIndexes:ColumnIndexes: is getting called, so it's not that. It's not the contents of the cells, either: I tried commenting out all my code to just leave the default cell image and text for each cell, and performance is the same. While scrolling, none of the cells get updated. (I put a breakpoint in tableView:viewForTableColumn:row: to make sure.)
My implementation has the following delegate methods:
tableView:viewForTableColumn:row: in the delegate; this creates and populates new cells via makeViewWithIdentifier:owner:
numberOfRowsInTableView: in the data source; this returns a constant number
tableView:sortDescriptorsDidChange: in the data source
That's it! Not very complicated, and yet.
I feel like I'm missing something completely obvious. What could be causing these redraws?
EDIT: Come to think of it, several other applications (uTorrent, Xcode) seem to exhibit the same slow scrolling behavior. You can really see it if you look at CPU usage while scrolling. On the other hand, Activity Monitor has buttery-smooth scrolling that barely spikes the CPU at all. How do I get that in my app?
EDIT 2: I think I found my mistake. According to Apple:
In iOS apps, Core Animation is always enabled and every view is backed
by a layer. In OS X, apps must explicitly enable Core Animation
support by doing the following:
Link against the QuartzCore framework. (iOS apps must link against this framework only if they use Core Animation interfaces explicitly.)
Enable layer support for one or more of your NSView objects by doing one of the following:
In your nib files, use the View Effects inspector to enable layer support for your views. The inspector displays checkboxes for
the selected view and its subviews. It is recommended that you enable
layer support in the content view of your window whenever possible.
For views you create programmatically, call the view’s setWantsLayer: method and pass a value of YES to indicate that the
view should use layers.
Enabling layer support in one of the preceding ways creates a
layer-backed view. With a layer-backed view, the system takes
responsibility for creating the underlying layer object and for
keeping that layer updated. In OS X, it is also possible to create a
layer-hosting view, whereby your app actually creates and manages the
underlying layer object. (You cannot create layer-hosting views in
iOS.) For more information on how to create a layer-hosting view, see
“Layer Hosting Lets You Change the Layer Object in OS X.”
I'll add an answer as soon as I fix my performance issues. With a cursory pass, my scrolling is still bumpy, but my CPU usage has dropped from 70% to 10% while scrolling.
For the record... Edit 2 by the OP makes the world of difference.
In iOS apps, Core Animation is always enabled and every view is backed
by a layer. In OS X, apps must explicitly enable Core Animation
support by doing the following:
Link against the QuartzCore framework. (iOS apps must link against
this framework only if they use Core Animation interfaces explicitly.)
Enable layer support for one or more of your NSView objects by doing
one of the following:
In your nib files, use the View Effects inspector to enable layer
support for your views. The inspector displays checkboxes for the
selected view and its subviews. It is recommended that you enable
layer support in the content view of your window whenever possible.
For views you create programmatically, call the view’s setWantsLayer:
method and pass a value of YES to indicate that the view should use
layers. Enabling layer support in one of the preceding ways creates a
layer-backed view. With a layer-backed view, the system takes
responsibility for creating the underlying layer object and for
keeping that layer updated. In OS X, it is also possible to create a
layer-hosting view, whereby your app actually creates and manages the
underlying layer object. (You cannot create layer-hosting views in
iOS.) For more information on how to create a layer-hosting view, see
“Layer Hosting Lets You Change the Layer Object in OS X.”

XCode iPad split view controller with detail views containing several form controls

Fairly new to Mac and XCode 3.2.6 and iPad. I have a fairly simple business data model to implement on the iPad, but can't seem to find the combination of views and controllers to use.
It's a simple data collection program, but there are too many data fields to fit on a single screen so I've resorted to the Split View approach.
I've got eight rows of table data on the left; RootViewController is the default UITableViewController. I'm trying to write the program such that when any of those table rows are selected, the view on the right (Detail View) gets redrawn and populated with a bunch of different controls (labels, buttons, text fields, etc.) that correspond to the selection on the left. Currently all the Details views are plain UIViewControllers.
For instance, the first "tab" might be titled "Personal", and I need to display fields to collect info such as Name, DOB, Height, Weight, etc. The next one might be "Address" where I need to collect Street, City, ZIP Code, etc. The next one might be "Employer", where I'd like to collect the employer's name, address, phone number, etc. These are mostly static and unchanging, but there are enough fields for about 8 screens worth.
I've got all this laid out in Interface Builder, but when I run it on the iPad simulator and click the very first button on the very first view, the connected delegate isn't called. I've put a breakpoint there and it's not being hit.
Is there some special magic to using simple UIViewControllers on the right side of a UISplitViewController, as far as letting them contain other simple Label, TextBox, and Button controls?
Also is there any special magic in that the framework built the original start-up code with a RootViewController.h/.m and DetailViewController.h/.m pair? Am I correct in thinking that a single detail view represents the entire iPad screen to the right of the Table View, and that to add more "pages" we need to write more files and .XIBs like DetailViewController?
Final question is how to implement the data model for this app. I noticed when the project was first auto-created, there weren't any source files for the model. (Maybe most of the predefined app types don't auto-generate anything for the model, but I understand that's a big part of model-view-controller paradigm.) Anyway these data fields on all the various views will eventually be part of a SQLite record that I'd like to save and load from storage. Where would I begin to wire all that stuff in to all the auto-generated "view centric" code?
If anyone has seen a "how to write real business apps for the iPad" website along the lines of anything like this, please post the link. I'm not trying to display jpegs of various fruits in a single (reused) view on the right side; I'm trying to display several real controls for real-world data collection for a real business app.
Thanks!
Basic things if you haven't already done them:
Have you connected the interface object the user is pressing from it's INSIDE TOUCH UP event to an IBOUTLET that then refreshes the right side?
If you have, and you've mucked about a bit (ie renaming and moving stuff around), try deleting it from the right-click event panel and then reconnecting it to the same IBOUTLET again (you don't have to delete any code).
Also, if you are counting on some event to fire that isn't firing, you should search on that (ie VIEWDIDLOAD NOT FIRING) because that can both occasionally be "broken" (ie no connection to the Files Owner) but more often one might misunderstand when that actually gets fired (ie VIEWDIDLOAD vs VIEWDIDAPPEAR vs VIEWWILLAPPEAR etc.)
For your data model, CoreData is your friend. It provides a modell-oriented approach and easily allows to persist data.
For your navigation needs, I think a tabBarController better suits your needs.
Changing the detail view from the master view can be troublesome, especially when using a NavigationController as detail view. The best way I've found is using the NSNotificationCenter.
When using UISplitview I strongly recommend to support the iPad only when it's a business requirement - there are some changes in iOs 8 that make easier to use.

Resources