(My issue is with WKInterfacePicker, but ideas for standard UIPickerView might also be applicable.)
I'm wondering if anyone has any suggestions on how I can limit the range of selectable values on a WKInterfacePicker?
To explain: Let's say I have two pickers, A and B. Each has a unique array of values. If the user moves picker A up or down, I make picker B move the opposite direction, by the same index change. The issue is if that movement of picker A is going to exceed the array of B's values (<0 or >array.count). I need to keep the range of selectable values on picker A within the limits of picker B, even though A may have index values higher or lower in its own array.
I have tried creating a 'slice' of picker A's values to match the range of picker B's limits, however this then alters the index numbering on picker A (i.e. index x no longer pertains to the same value).
I am ideally looking for a way to stop the user taking picker A past a given index range. Any ideas/thoughts greatly welcomed. Thanks in advance!
No answers received, but thought I would post how I worked this out in case anyone else has this issue.
First, some bugs seem to exist with the wkinterfacepicker in its current form, mainly around it not 'settling' correctly on a value under certain circumstances (bug raised with Apple). This means I had to work around this, using a number of the other methods available. Here is the approach I used:
(Assumes initial/previously selected values for both PickerA and
PickerB have been stored in variables.)
Use the pickerDidFocusmethod to trigger a calculation of the
current position of PickerB(from value stored above), and its
upper/lower limits. Calculate acceptable upper/lower values for PickerA based on this range.
When PickerA is changed, use the default #IBAction from the picker
change to store the selected value in another variable.
Use pickerDidSettleto wait for the PickerA movement to stop before
doing anything. Calculate change between old and new value of
PickerA, compare against limits calculated earlier. If within range,
make change to PickerB.
If outside of range for PickerB, pop alert message, and set a flag.
In willActivate for original InterfaceController, check for flag
and, if active, setSelectedItemIndex back to within acceptable
range.
This may seem a little overly complicated. The last step in particular may seem over the top, however sporadic/unreliable behaviour of the pickers I experienced, even when using pickerDidSettle, meant that I had to use this approach to guarantee that there was a pause before resetting the pickers.
Maybe this will help someone else!
Related
In my Vaadin 7 app, I call grid.recalculateColumnWidths(); after loading most grids. I do this because when I was refreshing one particular Grid, I noticed the column width was not changing. This fixed it with this one particular Grid, and probably a few others, but not with all grids. The documentation does not really explain a few things, and I was hoping someone could clarify some things so I can fix the problem:
When is it triggered? In other words, in the cases where it does not work, could it be a timing issue? For Vaadin Flow, I see some people advising doing something like grid.getElement().executeJs("setTimeout(() => { this.recalculateColumnWidths() }, 0)");, so I guess this is a long-standing issue. Also, if you look at the low-level API, you will see that it clearly says that you cannot rely on proper columns widths after calling this function, as it is not done immediately. When I step into it in the debugger, it looks like it adds it to a queue of actions to complete later, so that seems to confirm things. How can I improve my chances of the resize being triggered?
How does it handle columns where I explicitly set the width? If this is documented someplace (in API docs or in some posting someplace), I could not find it. When I stepped into the debugger, it was kind of hard to determine for sure.
If I added a button to force a resizing, calling this recalculateColumnWidths() method, similar to what some users did in Vaadin 14 here, would it work? So let's say we initialize the width to one value (so we purposely truncate some columns, forcing them to make the column bigger), and we want to fully show all content in all columns when they click this button, is there a way to do that? Maybe clear all explicit column sizes and let normal resize logic work?
Let me preface this answer by saying that column width (re)calculation is a complex and relatively expensive task. It needs to be done at the right time - not too early and not too late. If it's done too early, subsequent changes to layouting will mean that size calculation will need to be done again. If it's done too late, it means that the UI will take longer to become responsive again. Trying to "play it safe" by doing column width recalculation more often than needed is an easy source of performance degradation - a Grid can have a LOT of columns, so the cost of recalculation compounds easily.
There are many cases when column width recalculation is triggered. A couple of basic cases are during the layouting phase of the UI, or when a Grid is reattached, or when the inner width of the Grid changes (e.g. due to browser window resize), or when something is done to column sizes (e.g. min or max-width or expand ratio are set). Resizing is indeed queued as you can see here: https://github.com/vaadin/framework/blob/7.7/client/src/main/java/com/vaadin/client/widgets/Grid.java#L3280. It's definitely possible that there's a timing issue. Without the exact conditions of how a calculation goes wrong, it's hard to say when would be a good place to retry - there's no place where "everything is truly finally rendered so that you can schedule a little bit more rendering".
The size of fixed-width columns will not need to be calculated, so these columns should be ignorable from this point of view. In fact, if you can set a fixed width to all or most columns, it will most likely mean a significant performance improvement.
Yes, it could work.
In our iOS application, we are using core data and tied it with a table view using NSFetchedResultsController. The app is about "Chat" feature.
UI is same as that of iPhone "Messages" app. When we tap on a message, it displays the history and all the history grouped with time. The logic behind it is, if previous message and current message are received with a gap of 1 hr, then date & time stamp will be displayed over recent message.
My question is, how can I group the messages and fetch them so that I can show the date & time stamp as well as sender and receiver messages.
There are four types of message cells type - regular, group-start, group-middle, group-end. A group-start message is more than a hour after the last one but less than an hour to the next one. group-middle is less than an hour from the one before and after. group-end is close to the one before it, but more than hour to the one after it. regular is more than a hour before and after it.
There are two parts of this project. One is to display each type of cell correctly. The other is figure-out which type each message is. I assume you can figure out the UI stuff yourself (different padding, for each one, regular and group-start show the time, not rounding some corners, etc).
For each message to figure out its type, is not that hard - just look at the message before it and after it. It can be done in a single run through of the results - O(n). It could also be done lazily with a cache (ie each time a cell load check the message before and after it - save the answer in the cache for next time). If the cell sizes are different for different types then it make cause some weird jumping with estimatedRowHeight. You could also store the results of the type into core-data after you calculate it.
Be careful when a message is inserted to invalidate and recalculate the message cell type for the one above and below it. Also when calculating the message cell type account for situations where there isn't a next or previous cell.
I think you were hoping for some core-data magic - like some cleaver trick with sectionIndexKey. But it is really much more straight forward of just running through the array and calculating it.
Update:
Just to make it clear: don't use sections. Keep all the cells in one section. Just add the time to the top of the cell for the cell type group-start. It is a lot easier than dealing with sections especially when there are inserts that can cause and earlier cell to change from normal to group-start.
Pre-requisites - Environment: iOS 9.0 or above - using Swift 3.0.1
Thanks for your responses. I'm updating the question and trying to give a better understanding about the problem.
Posting code would help may be but I'm not allowed to post the code as I do not have the IP.
But I am trying to build something like calendar/program guide where you have events for each category for several days.
Imagine, categories on your left side in a column and they can be the sections of the collectionveiw and each category has events for several days which is a row.
CAT 1 : Event 1, Event 2 ... Event n
CAT 2 : Event 1, Event 2 ... Event n
CAT 3 : Event 1, Event 2 ... Event n
.
.
.
CAT m : Event 1, Event 2 ... Event n
Problem: The entire data is pretty dynamic and humongous. I can't prefetch all the records, they are about over 80-100K. It takes few minutes to download all the data and display it on the grid.
A user could select any day and any time and I have to scroll the collection view to that day and time and display those events for the categories. Also, user could obviously scroll in both directions to and browse the events in this case the events are loaded like infinite scroll fashion.
In the former option though, when the user jumps on to a particular day and time on the entire timeline and I have to skip loading the other previous events (as I do not have them yet - unknown) and display the events relevant to the user selected days and time.
I do not have all the IndexPaths in advance, to display on the screen, how can I skip events and dynamically update the collection view in parts like we load images dynamically and the ones which get loaded first and displayed earlier than others.
I'm using startDate of the events to calculate the xPosition, categories don't change often after they are loaded so we could somehow avoid reloading sections but items in those sections change all the time and they appear in a random fashion.
When the controller loads the first set of events are fetched from the server and displayed, now if the user decided to jump to some D-Day and T-Time which could be anywhere on the entire timeline I have to fetch the events for those dates and populate the items for relevant sections (visible on screen) and update the interface. This is where I have issues, where I do not have an proper approach.
Hope this is clearer.
I have "tried" to mock this up
UICollectionViewFlowLayout can help you achieve what you want...
https://developer.apple.com/reference/uikit/uicollectionviewflowlayout
https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/UsingtheFlowLayout/UsingtheFlowLayout.html
You have the same problem I had with my calendar project. The solution I have implemented will not work for you, but I am mentioning it here so that it might give you clues on how to solve it for your situation.
My calendar has a function where a user can scroll to some date way into the future. The problem was that date cells can be custom sizes. Therefore, since they are scrolling to some future date, in order for me to know the destination offset, I needed to know the offsets of cells 0 -to- destinationOffset because the cell sizes are different. This meant I had to query the sizes of all the cells in the middle which led to a 2-3 lag time (or in your case, a long download time).
So here was my solution.
I originally had a delegate function called sizeForCellsAtMonth which was called for every month in order to determine the size. I have now changed this function to be called only once.
The function now only has two parameters:
defaultSizeOfCells
exceptionToDefaults - this will be specific months where the cell sizes are different
Using this information, I can calculate the sizes of all months because I know the sizes before hand. So my problem was solved by changing the way I looked at my delegate. Maybe you can try looking somewhere along those lines or maybe my answer gave you clues of what you can do.
Is it possible to tell the iOS system not to set some property's value to default value when the cell scrolls of the screen? It does that automatically at random times. At runtime I set the property, than the cell goes of the screen, system sets the property to default, and I can't use it anymore.. What needs to be done to avoid this behaviour?
Don't even try.
Cells are objects that are only used to display things on the screen. They are not supposed to store any permanent information, they are supposed to be used for different rows of your table at any time.
Find a different place to store your information.
As a general rule, work with the rules of iOS. If you try to work against them, you will never succeed and just waste your time.
I wanted to use a UIPicker to simulate a drop-down menu and I found this code. It`s the second answer.
UIPickerView select and hide
Its exactly what I was locking for except for one thing. When I tap my TextField activating the method, like the author sais i should do, it takes a while for the UIPicker to show up. I would like to know if theres a way to make the code faster.
I think this happens because the method creates a UIPicker every time, but I`m not sure. Sorry if it is a stupid question.
Thanks
What I have done in the past is create the UIPickerView as a property of my UIViewController and then use the hidden property to display and dismiss it. You could even animate it up and down if you wanted to rather than just hide it. This way you will not be creating it every time. I could see how the creation would take a while if you are having to set it up with a lot of data or pulling the data from somewhere else.
So if I was you, I'd create it in viewDidLoad and then hide it until you are ready to use it instead of creating it each time. Or use an animation to take it on and off the screen.
One thing to remember, you are using the same UIPickerView each time, so you may want to set it up to some sort of default each time before you display it so it isn't just equal to whatever value they put in last upon display.
Likewise, I would create the toolbar and save it as a property as well and just hide or display both of them at the same time.