2

I am working on a Xamarin.Forms project with a ListView.

The XAML for the ListView is

<render:CustomListView x:Name="listview" ItemSelected="ItemSelected" ItemTapped="ItemTapped"></render:CustomListView>

And the C# is

public void ItemTapped(object sender, ItemTappedEventArgs e)
    {
        var Selected = e.Item as Classes.NavigationItem;
        //Handle clicked
        }
       ((ListView)sender).SelectedItem = null;

    }

    private void ItemSelected(object sender, SelectedItemChangedEventArgs e)
    {
        ((ListView)sender).SelectedItem = null;
    }

My custom renderers are

Android (Custom ListView):

public class NavigationListViewAndroid : ListViewRenderer
{
    #pragma warning disable CS0618 // Type or member is obsolete
    public NavigationListViewAndroid() { }
    #pragma warning restore CS0618 // Type or member is obsolete

    public NavigationListViewAndroid(Context context) : base(context)
    {

    }

    protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.ListView> e)
    {
        base.OnElementChanged(e);
        Control.SetSelector(Android.Resource.Color.DarkerGray);
    }

}

iOS (ViewCell):

public class NavigationViewCelliOS : ViewCellRenderer
{
    public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
    {
        var cell = base.GetCell(item, reusableCell, tv);
        cell.SelectionStyle = UITableViewCellSelectionStyle.Gray;

        return cell;
    }
}

My problems are :

Android: It selected the row but stays selected until you click another one (for both), I want it to deselect when you let go

iOS: Never highlights gray at all even if held down

Dan
  • 1,100
  • 2
  • 13
  • 36
  • What is the desired behaviour? Button like i.e. a click to push a details page or something else? – Kay Apr 06 '18 at 06:51
  • @Kay Yes, when you click the item it takes you to a detail page. When held down staying highlighted but letting go I want to unselect it – Dan Apr 06 '18 at 06:56
  • @Dan On iOS the cell can be highlighted when we hold down the cell. Do you want to achieve the same effect on Android? – Ax1le Apr 06 '18 at 07:49

4 Answers4

3

To apply background color to list view selected item follow these steps:

Make custom control:

using Xamarin.Forms;

namespace xamformsdemo.CustomControls
{
  public class ExtendedViewCell : ViewCell
  {
    public static readonly BindableProperty SelectedBackgroundColorProperty =
    BindableProperty.Create("SelectedBackgroundColor", 
                            typeof(Color), 
                            typeof(ExtendedViewCell), 
                            Color.Default);

    public Color SelectedBackgroundColor
    {
       get { return (Color)GetValue(SelectedBackgroundColorProperty); }
       set { SetValue(SelectedBackgroundColorProperty, value); }
    }
  }
}

Android Renderer:

[assembly: ExportRenderer(typeof(ExtendedViewCell), typeof(ExtendedViewCellRenderer))]
namespace xamformsdemo.Droid.CustomRenderers
{
  public class ExtendedViewCellRenderer : ViewCellRenderer
  {

private Android.Views.View _cellCore;
private Drawable _unselectedBackground;
private bool _selected;

protected override Android.Views.View GetCellCore(Cell item, 
                                                  Android.Views.View convertView, 
                                                  ViewGroup parent, 
                                                  Context context)
{
  _cellCore = base.GetCellCore(item, convertView, parent, context);

  _selected = false;
  _unselectedBackground = _cellCore.Background;

  return _cellCore;
}

protected override void OnCellPropertyChanged(object sender, PropertyChangedEventArgs args)
{
  base.OnCellPropertyChanged(sender, args);

  if (args.PropertyName == "IsSelected")
  {
    _selected = !_selected;

    if (_selected)
    {
      var extendedViewCell = sender as ExtendedViewCell;
      _cellCore.SetBackgroundColor(extendedViewCell.SelectedBackgroundColor.ToAndroid());
    }
    else
    {
      _cellCore.SetBackground(_unselectedBackground);
    }
  }
}
  }

}

iOS Renderer:

[assembly: ExportRenderer(typeof(ExtendedViewCell), typeof(ExtendedViewCellRenderer))]
namespace xamformsdemo.iOS.CustomRenderers
{
  public class ExtendedViewCellRenderer : ViewCellRenderer
  {
    public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
   {
      var cell = base.GetCell(item, reusableCell, tv);
      var view = item as ExtendedViewCell;
      cell.SelectedBackgroundView = new UIView
       {
         BackgroundColor = view.SelectedBackgroundColor.ToUIColor(),
       };

      return cell;
    }

  }
}

Use in XAML:

<ListView.ItemTemplate>
  <DataTemplate>
    <customControls:ExtendedViewCell SelectedBackgroundColor="Teal">
      <ViewCell.View>
        <StackLayout HorizontalOptions="FillAndExpand" 
                     VerticalOptions="FillAndExpand" Orientation="Vertical" 
                     Padding="4" Spacing="8">
          <Label TextColor="White" Text="{Binding .ItemName}"/>
          <Label TextColor="Yellow" Text="{Binding .LastUpdated, StringFormat='Last seen: {0:HH:mm:ss}'}"/>
        </StackLayout>
      </ViewCell.View>
    </customControls:ExtendedViewCell>
  </DataTemplate>
</ListView.ItemTemplate>

You can refer this link below to solve problem: https://blog.wislon.io/posts/2017/04/11/xamforms-listview-selected-colour

MShah
  • 1,247
  • 9
  • 14
  • I tried the code and it works on Android except on iOS it stays highlighted – Dan Apr 06 '18 at 09:00
  • Also setting it so SelectedBackgroundColor="LightGray" still seems to make it light blue on android – Dan Apr 06 '18 at 09:51
  • Its working fine for me,So I guess you should try to use Hexcode instead of providing name of the Color i.e.SelectedBackgroundColor="#F2F2F2" for both the platforms to make it similar for android and iOS. – MShah Apr 06 '18 at 10:21
  • I tried using a hex code but still highlights as blue, iOS doesn't seem to highlight at all – Dan Apr 06 '18 at 21:55
  • Lets do further discussion in chat, as I need to see your actual code for that, make sure you have removed color from your android custom listview renderer and only using this view cell renderer for the same to avoid conflicts. – MShah Apr 07 '18 at 03:54
  • I don't know how to move it to the chat but here is my code https://gist.github.com/KingBlueSapphire/f055609f32e05b79601f29a38dce2774 – Dan Apr 07 '18 at 05:23
  • @Dan I guess you are missing some syntax, try to go with that as I have commented here https://gist.github.com/KingBlueSapphire/f055609f32e05b79601f29a38dce2774 – MShah Apr 07 '18 at 05:56
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/168435/discussion-between-dan-and-mansi-shah). – Dan Apr 07 '18 at 06:00
  • @Dan please find my code on github, its working properly for android and iOS https://github.com/MansiShah04/CustomLitViewCell – MShah Apr 09 '18 at 08:57
  • 1
    So I've been testing it in Android 4.1, I tested it in 6.0 and it worked. Is there any way to make this support earlier devices – Dan Apr 10 '18 at 02:18
  • It supports Android 4.4 and above only. – MShah Apr 10 '18 at 08:20
1

I had same problem, I was using ItemSelected, but the selected item wasn't getting deselected unless until I select any other item in the ListView. I replace ItemSelected by ItemTapped. It worked for me.

Abhishek
  • 79
  • 10
1

I prefer to use the SelectedItem property to handle simple clicks. This works platform independent and everything can be done in the view model code.

The trick is to set the property null again to deselect the item immediately after evaluating it (in hte sample I use it for initialising another view model).

XAML:

<ListView ItemsSource="{Binding Items}" 
    SelectedItem="{Binding SelectedProduct, Mode=TwoWay}">

ViewModel.cs:

public Command<IProduct> ViewDetailsCommand;
public ViewModel()
{
     ViewDetailsCommand = new Command<IProduct>(async s => await ViewDetails(s));
}

public IProduct SelectedProduct
{
    get { return _selectedProduct; }
    set
    {
        if (value != _selectedProduct)
        {
            SetProperty(ref _selectedProduct, value);
            if (value != null)
            {
                ViewDetailsCommand.Execute(value);
            }
        }
    }
}

private async Task ViewDetails(IProduct product)
{
    var viewModel = AppContainer.Container.Resolve<ProductDetailsViewModel>();
    viewModel.Initialise(this, product as ShoppingListItemViewModel);
    SelectedProduct = null;
    await _pageNavigator.PushModalAsync(viewModel);
}
Kay
  • 12,918
  • 4
  • 55
  • 77
1

On Android If you only want to change the color when use clicks the ListView's Item. You can modify the style:

Before Api 21, create a xml file in the drawable folder:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:drawable="@color/colorPrimary" android:state_pressed="false"/>  
  <item android:drawable="@color/colorAccent" android:state_pressed="true"/>  
  <item android:drawable="@color/colorPrimary"/>                              
</selector>

On Api 21+, under the drawable-v21 folder create the file with same name:

<?xml version="1.0" encoding="utf-8"?>
<ripple
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/colorAccent">
  <item android:drawable="@color/colorPrimaryDark"/>
</ripple>

Then change the style in the renderer:

// f_selector is the xml file's name
Control.SetSelector(Resource.Drawable.f_selector);

At last change the color in the resource file colors.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <color name="colorPrimary">#3F51B5</color> <!--original background color api21- -->
  <color name="colorPrimaryDark">#FFFFFF</color> <!--original background color api21+ -->
  <color name="colorAccent">#FF313030</color> 
</resources>
Ax1le
  • 6,563
  • 2
  • 14
  • 61