Xamarin - Deselect Listview Item does not work properly in iOS - ios

I have a listview and I want an Item to deselect if I tap it again. So basically I tap an Item it gets selected I tap it again it gets deselected.
My Code is working just fine on Android. It also works on iOS the only thing that doesn't work is if I tap an Item its background color changes but if I deselect it its background color should change back. That happens on Android but not on iOS. Any ideas why "mylistview.selecteditem = null" works properly on Android but not on iOS?
public void AnwesenheitTapped(object sender, ItemTappedEventArgs args)
{
if (args.Item as Anwesenheit != Anwesenheit)
{
Anwesenheit = args.Item as Anwesenheit;
ViewModel.Anwesenheit = args.Item as Anwesenheit;
if (Anwesenheit == null)
{
return;
}
ViewModel.AlsAbwesendEintragenButton = true;
ViewModel.Datum = Anwesenheit.Datum;
AnwesenheitenDatum.IsEnabled = false;
if (Anwesenheit.Anmeldungsart == "Früh")
{
Anmeldungsart.SelectedIndex = 0;
}
else if (Anwesenheit.Anmeldungsart == "Mittags")
{
Anmeldungsart.SelectedIndex = 1;
}
else
{
Anmeldungsart.SelectedIndex = 2;
}
AnwesenheitenLabel.Text = "Anwesenheit bearbeiten:";
AnwesenheitenButton.Text = "Anwesenheit bearbeiten";
ViewModel.Edit = true;
}
else
{
Anwesenheit = null;
ViewModel.Datum = DateTime.Today;
AnwesenheitenDatum.IsEnabled = true;
ViewModel.AlsAbwesendEintragenButton = false;
Anmeldungsart.SelectedIndex = 0;
ViewModel.Edit = false;
AnwesenheitenLabel.Text = "Neue Anwesenheit:";
AnwesenheitenButton.Text = "Neue Anwesenheit hinzufügen";
BetreuungsoptionenListView.SelectedItem = null;
}
}

What is your Xamarin Forms version, there is a bug in Xamarin Forms 3.5 for iOS listview, which is fixed in version 3.6

Related

Xamarin iOS - Text Changed event not showing results

Xamarin iOS is testing me lately. I have a form which has as Entry value for searching. This entry control has a text changed event. All works great , event executes and values passed as expected however the results dont appear on screen.
If i rotate the device, in this case and ipad, the results show. Everything in Android works as expected. Frustrating
CancellationTokenSource _cts;
private void Search_TextChanged(object sender, TextChangedEventArgs e)
{
try
{
_cts?.Cancel(); // cancel previous search
}
catch { } // in case previous search completed
ShowResults((Entry)sender);
}
private async void ShowResults(Entry entry)
{
using (_cts = new CancellationTokenSource())
{
try
{
await Task.Delay(TimeSpan.FromSeconds(1), _cts.Token); // buffer
using (UserDialogs.Instance.Loading("Loading. . ."))
{
ObservableCollection<TMDB_Movie> itemSourceCollection = new ObservableCollection<TMDB_Movie>();
MovieSearchVM context = (MovieSearchVM)BindingContext;
try
{
if (!IsPublicCollection)
{
var results = PrivateCollection.Where(x => x.Title.Contains(entry.Text));
foreach (TMDB_Movie movie in results)
{
movie.PublicCollection = true;
movie.Type = "Digital";
itemSourceCollection.Add(movie);
}
}
else
{
if (PhysicalDevice.HasInternetConnection())
{
TMDB_Request request = new TMDB_Request();
TMDB_Movies movies = await request.ByMovieName(entry.Text, CustomSettings.GetSettings().Language);
int i = 0;
foreach (var movie in movies.Results)
{
if (i < 10)
{
FanartTv tv = new FanartTv();
movie.Movieposter = await tv.GetSingleMoviePoster(movie.Id);
if (movie.Release_date != null)
{
char[] Separator = new char[] { '-' };
string[] year = movie.Release_date.Split(Separator, StringSplitOptions.None);
movie.Release_year = year[0];
}
movie.PublicCollection = true;
itemSourceCollection.Add(movie);
i++;
}
else
{
break;
}
}
}
}
context.MovieCollection = itemSourceCollection;
}
catch { }
}
}
catch { }
}
}
View Model
private ObservableCollection<TMDB_Movie> _MovieCollection = new ObservableCollection<TMDB_Movie>();
public ObservableCollection<TMDB_Movie> MovieCollection
{
get { return _MovieCollection; }
set
{
_MovieCollection = value;
RaisePropertyChanged("MovieCollection");
}
}
XAML
<Grid Style="{StaticResource StyleBaseGrid}" Grid.Row="2" HorizontalOptions="FillAndExpand" >
<SfListView:SfListView x:Name="GridMovieCollection"
ItemsSource="{Binding MovieCollection}"
ItemTemplate="{StaticResource StandardPosterTemplate}"
Margin="-5,0,0,0"
ItemSize="125"
ItemSpacing="0,0,0,0"
AutoFitMode="None"
SelectionBackgroundColor="Transparent"
ItemHolding="GridMovieCollection_ItemHolding"
ItemTapped="GridMovieCollection_ItemTapped" >
</SfListView:SfListView>
</Grid>
I have no clue why rotation solves this but i guess it updates the controls width and height properties and refreshes the screen.
Any ideas how i can force refresh the screen or if there is anything wrong with my code?
Android look

SpriteWidget: App doesn't response to handleEvent in NodeWithSize

I created a widget, added some Sprites and made some animation. I want to add some user interaction but handelEvent method is not working. I already set userInteractionEnabled to true.
I tried debugging and place a breakpoint inside the handleEvent method but it didn't stop when I touched the screen.
class MainSceneBackgroundNode extends NodeWithSize {
Sprite _logo;
RepeatedImage _background;
GuyImage _guy;
int _i = 0;
int _j = 0;
int _dir = -1;
MainSceneBackgroundNode() : super(new Size(2560.0, 1440.0)) {
userInteractionEnabled = true;
handleMultiplePointers = false;
// Add background
_background = new RepeatedImage(_imageMap["assets/background.png"]);
addChild(_background);
_guy = new GuyImage();
addChild(_guy);
_logo = new Sprite.fromImage(_imageMap["assets/logo.gif"]);
_logo.pivot = Offset.zero;
_logo.size = new Size(912, 486);
_logo.position = new Offset(824, 10);
addChild(_logo);
}
#override
bool handleEvent(SpriteBoxEvent event) {
if (event.type == PointerDownEvent) {
if (event.boxPosition.dx < 1280) {
_dir = -1;
} else {
_dir = 1;
}
}
return true;
}
...
}
Any suggestion will be appreciated. I don't know what else to do.
Thanks in Advance.

XNA Controls Settings

I have a huge problem with editing controls for my game.. I have an ingame button and when you click it. The "Choose your key.." text appears, but I don't know how to actually set it up..
I have made a "waiting for input" bool.. THIS IS NOT THE REAL CODE IT'S HOW I IMAGINE IT TO BE
if (buttonIsClicked) waitinForInput = true;
while(waitingForInput)
{
kbState = Keyboard.GetState();
somehow convert it to Keys.(STH);
if (Keys.STH != defaultKeys)
{
defaultKeys = Keys.STH;
waitingForInput = false;
}
}
Is there a way to do this.. Simpliest as I can? And sorry for my bad english.. Made this in a hurry and not my native language..
Thanks for any help.. :-)
Something like this:
KeyboardState currentKeyboardState = new KeyBoardState();
KeyboardState previousKeyboardState = new KeyBoardState();
Keys jumpKey = Keys.Space;
public void handleInput()
{
lastKeyboardState = currentKeyboardState;
currentKeyboardState = Keyboard.GetState(PlayerIndex.One);
bool waitingForKey = false;
if(currentKeyboardState.IsKeyDown(Keys.A) && waitingForKey == false)
{
waitingForKey = true;
}
if(waitingForKey == true)
{
//currentKeyboardState.GetPressedKeys() returns a list of pressed keys,
//So, currentKeyboardState.GetPressedKeys()[0] returns the first pressed key
if(currentKeyboardState.GetPressedKeys().Count() > 0)
{
jumpKey = currentKeyboardState.GetPressedKeys()[0];
waitingForKey = false;
}
}
}

iOS UIAutomation UIAElement.isVisible() throwing stale response?

I'm trying to use isVisible() within a loop to create a waitForElement type of a function for my iOS UIAutomation. When I try to use the following code, it fails while waiting for an element when a new screen pops up. The element is clearly there because if I do a delay(2) before tapping the element it works perfectly fine. How is everyone else accomplishing this, because I am at a loss...
Here's the waitForElement code that I am using:
function waitForElement(element, timeout, step) {
if (step == null) {
step = 0.5;
}
if (timeout == null) {
timeout = 10;
}
var stop = timeout/step;
for (var i = 0; i < stop; i++) {
if (element.isVisible()) {
return;
}
target.delay(step);
}
element.logElement();
throw("Not visible");
}
Here is a simple wait_for_element method that could be used:
this.wait_for_element = function(element, preDelay) {
if (!preDelay) {
target.delay(0);
}
else {
target.delay(preDelay);
}
var found = false;
var counter = 0;
while ((!found) && (counter < 60)) {
if (!element.isValid()) {
target.delay(0.5);
counter++;
}
else {
found = true;
target.delay(1);
}
}
}
I tend to stay away from my wait_for_element and look for any activityIndicator objects on screen. I use this method to actual wait for the page to load.
this.wait_for_page_load = function(preDelay) {
if (!preDelay) {
target.delay(0);
}
else {
target.delay(preDelay);
}
var done = false;
var counter = 0;
while ((!done) && (counter < 60)) {
var progressIndicator = UIATarget.localTarget().frontMostApp().windows()[0].activityIndicators()[0];
if (progressIndicator != "[object UIAElementNil]") {
target.delay(0.25);
counter++;
}
else {
done = true;
}
}
target.delay(0.25);
}
Here is a simple and better one using recursion. "return true" is not needed but incase u want it.
waitForElementToDismiss:function(elementToWait,waitTime){ //Using recursion to wait for an element. pass in 0 for waitTime
if(elementToWait && elementToWait.isValid() && elementToWait.isVisible() && (waitTime < 30)){
this.log("Waiting for element to invisible");
target.delay(1);
this.waitForElementToDismiss(elementToWait, waitTime++);
}
if(waitTime >=30){
fail("Possible login failed or too long to login. Took more than "+waitTime +" seconds")
}
return true;
}
Solution
I know this is an old question but here is my solution for a situation where I have to perform a repetitive task against a variable timed event. Since UIAutomation runs on javascript I use a recursive function with an empty while loop that checks the critical control state required before proceeding to the next screen. This way one never has to hard code a delay.
// Local target is the running simulator
var target = UIATarget.localTarget();
// Get the frontmost app running in the target
var app = target.frontMostApp();
// Grab the main window of the application
var window = app.mainWindow();
//Get the array of images on the screen
var allImages = window.images();
var helpButton = window.buttons()[0];
var nextButton = window.buttons()[2];
doSomething();
function doSomething ()
{
//only need to tap button for half the items in array
for (var i=0; i<(allImages.length/2); i++){
helpButton.tap();
}
//loop while my control is NOT enabled
while (!nextButton.isEnabled())
{
//wait
}
//proceed to next screen
nextButton.tap();
//go again
doSomething();
}

Flash: How to preload upcoming SWF while current one plays

I have a Flash slideshow that plays SWFs listed in an XML file. I would like to have the upcoming SWF load while the current one displays. I've tried all sorts of combinations of LoadMovie and LoadMovieNum, including creating an empty movie clip, but there's something I'm just not getting.
Right now, after making the first round through all the files, it transitions smoothly from slide to slide, but I'd like for it to preload so that it transitions without the "Loading..." screen the first time around.
It can be viewed here: slideshow
Where should I put the LoadMovie line to load the next file (image[p+1]), and how should it look?
function loadXML(loaded) {
if (loaded) {
xmlNode = this.firstChild;
image = [];
description = [];
total = xmlNode.childNodes.length;
for (i=0; i<total; i++) {
image[i] = xmlNode.childNodes[i].childNodes[0].firstChild.nodeValue;
description[i] = xmlNode.childNodes[i].childNodes[1].firstChild.nodeValue;
}
firstImage();
} else {
content = "file not loaded!";
}
}
xmlData = new XML();
xmlData.ignoreWhite = true;
xmlData.onLoad = loadXML;
xmlData.load("xmlfile.xml");
/////////////////////////////////////
back_btn.onRelease = function ()
{
backImage();
};
next_btn.onRelease = function ()
{
nextImage();
};
p = 0;
function nextImage() {
if (p<(total-1)) {
p++;
trace(this);
_root.mc_loadfile.loadMovie (image[p]);
_root.movie_name.text = image[p];
next_btn._visible = true;
back_btn._visible = true;
if (getBytesLoaded() == getBytesTotal())
slideshow();
}
else if (p == (total-1)) {
p = 0;
firstImage();
}
}
function backImage() {
clearInterval(myInterval);
if (p>0) {
--p;
_root.mc_loadfile.loadMovie (image[p]);
_root.movie_name.text = image[p];
next_btn._visible = true;
if (p != 0) {
back_btn._visible = true;
}
else {
back_btn._visible = false;
}
slideshow();
}
}
I'd appreciate any help.
You can do it with the MovieClipLoader class. A brief tutorial can be found at actionscript.org, or you can check the docs on it.

Resources