Skip to content
This repository was archived by the owner on May 15, 2025. It is now read-only.

Commit a3e1583

Browse files
Add multiple selection to the MaterialChipsGroup
1 parent ca19ec9 commit a3e1583

5 files changed

Lines changed: 176 additions & 37 deletions

File tree

MaterialDesignControls.nuspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
33
<metadata minClientVersion="2.8.1">
44
<id>Plugin.MaterialDesignControls</id>
5-
<version>1.10.3</version>
5+
<version>1.10.4</version>
66
<title>MaterialDesignControls Plugin for Xamarin Forms</title>
77
<authors>Horus</authors>
88
<owners>AgustinBonillaHorus</owners>

example/ExampleMaterialDesignControls/Pages/MaterialChipsPage.xaml

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,32 @@
2525
<material:MaterialChips Grid.Column="2" Grid.Row="1" IsSelected="false" IsEnabled="false" Text="Option F" />
2626

2727
</Grid>
28-
<material:MaterialLabel Text="Chips group control" Margin="0,24,0,0" />
29-
<material:MaterialChipsGroup LabelText="Sizes" SelectedItem="{Binding SelectedSizes}" ItemsSource="{Binding Sizes}" AssistiveText="{Binding Error}" AnimateError="True" />
28+
29+
<BoxView
30+
HeightRequest="1"
31+
BackgroundColor="LightGray" />
32+
33+
<material:MaterialLabel
34+
Text="Chips group control"
35+
Margin="0,24,0,0" />
36+
37+
<material:MaterialChipsGroup
38+
LabelText="Sizes"
39+
SelectedItem="{Binding SelectedSizes}"
40+
ItemsSource="{Binding Sizes}"
41+
AssistiveText="{Binding Error}"
42+
AnimateError="True"
43+
ChipsFlexLayoutPercentageBasis="0.33"/>
44+
45+
<material:MaterialChipsGroup
46+
LabelText="Colors"
47+
IsMultipleSelection="True"
48+
SelectedItems="{Binding SelectedColors}"
49+
ItemsSource="{Binding Colors}" />
50+
51+
<BoxView
52+
HeightRequest="1"
53+
BackgroundColor="LightGray" />
3054

3155
<material:MaterialLabel Text="Filters" Margin="0,24,0,0" />
3256
<FlexLayout Wrap="Wrap" Direction="Row" HorizontalOptions="FillAndExpand">

example/ExampleMaterialDesignControls/ViewModels/MaterialChipViewModel.cs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System.Collections.Generic;
22
using System.Collections.ObjectModel;
33
using System.Threading.Tasks;
44
using System.Windows.Input;
@@ -32,6 +32,22 @@ public string SelectedSizes
3232
set { SetProperty(ref selectedSizes, value); }
3333
}
3434

35+
private ObservableCollection<string> colors;
36+
37+
public ObservableCollection<string> Colors
38+
{
39+
get { return colors; }
40+
set { SetProperty(ref colors, value); }
41+
}
42+
43+
private List<string> selectedColors;
44+
45+
public List<string> SelectedColors
46+
{
47+
get { return selectedColors; }
48+
set { SetProperty(ref selectedColors, value); }
49+
}
50+
3551
private string error;
3652

3753
public string Error
@@ -63,14 +79,17 @@ public ProductDetailsViewModel()
6379
})));
6480

6581
this.Sizes = new ObservableCollection<string> { "6", "6.5", "7", "7.5", "8" };
82+
83+
this.Colors = new ObservableCollection<string> { "Red", "White", "Green", "Sky blue", "Black", "Gray", "Light Gray" };
6684
}
6785

6886
private async void OnTapCommand()
6987
{
7088
if (!string.IsNullOrEmpty(this.SelectedSizes))
7189
{
7290
this.Error = null;
73-
await this.DisplayAlert.Invoke("", "Saved", "Ok");
91+
var colors = SelectedColors != null ? string.Join(", ", SelectedColors) : string.Empty;
92+
await this.DisplayAlert.Invoke("Saved", $"Size: {SelectedSizes} - Colors: {colors}", "Ok");
7493
}
7594
else
7695
{
@@ -90,4 +109,4 @@ public Item(string name, ICommand cmd)
90109
this.TapCommand = cmd;
91110
}
92111
}
93-
}
112+
}

src/MaterialDesignControls/Controls/MaterialChipsGroup.xaml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
<ContentView.Content>
77
<StackLayout Spacing="2">
88
<controls:MaterialLabel x:Name="lblLabel" IsVisible="false" LineBreakMode="NoWrap" Margin="14,0,14,2" HorizontalTextAlignment="Start" />
9-
<ScrollView Orientation="Horizontal" HorizontalScrollBarVisibility="Never">
10-
<StackLayout x:Name="stcContainer" Orientation="Horizontal" Spacing="12" Padding="12,0">
11-
</StackLayout>
12-
</ScrollView>
9+
<FlexLayout
10+
x:Name="flexContainer"
11+
Wrap="Wrap"
12+
Direction="Row"
13+
JustifyContent="Start"
14+
AlignContent="Start" />
1315
<controls:MaterialLabel x:Name="lblAssistive" IsVisible="false" LineBreakMode="NoWrap" Margin="14,2,14,0" HorizontalTextAlignment="Start" />
1416
</StackLayout>
1517
</ContentView.Content>

src/MaterialDesignControls/Controls/MaterialChipsGroup.xaml.cs

Lines changed: 121 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections;
33
using System.Collections.Generic;
4+
using System.Linq;
45
using System.Runtime.CompilerServices;
56
using Plugin.MaterialDesignControls.Animations;
67
using Xamarin.Forms;
@@ -50,6 +51,24 @@ public Thickness ChipsPadding
5051
set { SetValue(ChipsPaddingProperty, value); }
5152
}
5253

54+
public static readonly BindableProperty ChipsMarginProperty =
55+
BindableProperty.Create(nameof(ChipsMargin), typeof(Thickness), typeof(MaterialChipsGroup), defaultValue: new Thickness(6));
56+
57+
public Thickness ChipsMargin
58+
{
59+
get { return (Thickness)GetValue(ChipsMarginProperty); }
60+
set { SetValue(ChipsMarginProperty, value); }
61+
}
62+
63+
public static readonly BindableProperty ChipsFlexLayoutBasisPercentageProperty =
64+
BindableProperty.Create(nameof(ChipsFlexLayoutPercentageBasis), typeof(double), typeof(MaterialChipsGroup), defaultValue: 0.0);
65+
66+
public double ChipsFlexLayoutPercentageBasis
67+
{
68+
get { return (double)GetValue(ChipsFlexLayoutBasisPercentageProperty); }
69+
set { SetValue(ChipsFlexLayoutBasisPercentageProperty, value); }
70+
}
71+
5372
public static readonly new BindableProperty IsEnabledProperty =
5473
BindableProperty.Create(nameof(IsEnabled), typeof(bool), typeof(MaterialChipsGroup), defaultValue: true);
5574

@@ -69,11 +88,11 @@ public string LabelText
6988
}
7089

7190
public static readonly BindableProperty ItemsSourceProperty =
72-
BindableProperty.Create(nameof(ItemsSource), typeof(IEnumerable), typeof(MaterialChipsGroup), defaultValue: null, propertyChanged: OnItemsSourceChanged);
91+
BindableProperty.Create(nameof(ItemsSource), typeof(IEnumerable<string>), typeof(MaterialChipsGroup), defaultValue: null, propertyChanged: OnItemsSourceChanged);
7392

74-
public IEnumerable ItemsSource
93+
public IEnumerable<string> ItemsSource
7594
{
76-
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
95+
get { return (IEnumerable<string>)GetValue(ItemsSourceProperty); }
7796
set { SetValue(ItemsSourceProperty, value); }
7897
}
7998

@@ -86,6 +105,15 @@ public string SelectedItem
86105
set { SetValue(SelectedItemProperty, value); }
87106
}
88107

108+
public static readonly BindableProperty SelectedItemsProperty =
109+
BindableProperty.Create(nameof(SelectedItems), typeof(List<string>), typeof(MaterialChipsGroup), defaultValue: null, propertyChanged: OnSelectedItemsChanged, defaultBindingMode: BindingMode.TwoWay);
110+
111+
public List<string> SelectedItems
112+
{
113+
get { return (List<string>)GetValue(SelectedItemsProperty); }
114+
set { SetValue(SelectedItemsProperty, value); }
115+
}
116+
89117
public static readonly BindableProperty AssistiveTextProperty =
90118
BindableProperty.Create(nameof(AssistiveText), typeof(string), typeof(MaterialChipsGroup), defaultValue: null);
91119

@@ -239,33 +267,57 @@ public bool AnimateError
239267
set { SetValue(AnimateErrorProperty, value); }
240268
}
241269

270+
public static readonly BindableProperty IsMultipleSelectionProperty =
271+
BindableProperty.Create(nameof(IsMultipleSelection), typeof(bool), typeof(MaterialChipsGroup), defaultValue: false);
272+
273+
public bool IsMultipleSelection
274+
{
275+
get { return (bool)GetValue(IsMultipleSelectionProperty); }
276+
set { SetValue(IsMultipleSelectionProperty, value); }
277+
}
278+
242279
#endregion Properties
243280

244281
#region Methods
245282

283+
// Single selection
246284
private static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
247285
{
248286
var control = (MaterialChipsGroup)bindable;
249-
if (control.stcContainer.Children != null)
287+
if (control.flexContainer.Children != null && control.SelectedItem != null)
250288
{
251-
foreach (var item in control.stcContainer.Children)
289+
foreach (var item in control.flexContainer.Children)
252290
{
253291
if (item != null && item is MaterialChips)
254-
{
255292
((MaterialChips)item).IsSelected = ((MaterialChips)item).Text.Equals(control.SelectedItem);
256-
}
293+
}
294+
}
295+
}
296+
297+
// Multiple selection
298+
private static void OnSelectedItemsChanged(BindableObject bindable, object oldValue, object newValue)
299+
{
300+
var control = (MaterialChipsGroup)bindable;
301+
if (control.flexContainer.Children != null && control.SelectedItems != null && control.SelectedItems.Any())
302+
{
303+
foreach (var item in control.flexContainer.Children)
304+
{
305+
if (item != null && item is MaterialChips)
306+
((MaterialChips)item).IsSelected = control.SelectedItems.Contains(((MaterialChips)item).Text);
257307
}
258308
}
259309
}
260310

261311
private static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
262312
{
263313
var control = (MaterialChipsGroup)bindable;
264-
control.stcContainer.Children.Clear();
314+
control.flexContainer.Children.Clear();
265315
if (!Equals(newValue, null) && newValue is IEnumerable)
266316
{
267317
foreach (var item in (IEnumerable)newValue)
268318
{
319+
// TODO: apply ChipsFlexLayoutBasis???
320+
269321
var materialChips = new MaterialChips
270322
{
271323
HorizontalOptions = LayoutOptions.FillAndExpand,
@@ -274,6 +326,7 @@ private static void OnItemsSourceChanged(BindableObject bindable, object oldValu
274326
FontFamily = control.FontFamily,
275327
CornerRadius = control.CornerRadius,
276328
Padding = control.ChipsPadding,
329+
Margin = control.ChipsMargin,
277330
BackgroundColor = control.BackgroundColor,
278331
TextColor = control.TextColor,
279332
SelectedBackgroundColor = control.SelectedBackgroundColor,
@@ -283,12 +336,23 @@ private static void OnItemsSourceChanged(BindableObject bindable, object oldValu
283336
DisabledSelectedBackgroundColor = control.DisabledSelectedBackgroundColor,
284337
DisabledSelectedTextColor = control.DisabledSelectedTextColor
285338
};
286-
if (control.SelectedItem != null)
339+
340+
if (control.IsMultipleSelection)
341+
{
342+
if (control.SelectedItems != null && control.SelectedItems.Any())
343+
materialChips.IsSelected = control.SelectedItems.Contains(materialChips.Text);
344+
}
345+
else
287346
{
288-
materialChips.IsSelected = materialChips.Text.Equals(control.SelectedItem);
347+
if (control.SelectedItem != null)
348+
materialChips.IsSelected = materialChips.Text.Equals(control.SelectedItem);
289349
}
350+
290351
materialChips.IsSelectedChanged += control.MaterialChips_IsSelectedChanged;
291-
control.stcContainer.Children.Add(materialChips);
352+
control.flexContainer.Children.Add(materialChips);
353+
354+
if (control.ChipsFlexLayoutPercentageBasis > 0 && control.ChipsFlexLayoutPercentageBasis <= 1)
355+
FlexLayout.SetBasis(materialChips, new FlexBasis((float)control.ChipsFlexLayoutPercentageBasis, true));
292356
}
293357
}
294358
}
@@ -297,27 +361,58 @@ private void MaterialChips_IsSelectedChanged(object sender, EventArgs e)
297361
{
298362
if (sender is MaterialChips)
299363
{
300-
if (((MaterialChips)sender).IsSelected)
364+
if (IsMultipleSelection)
301365
{
302-
this.SelectedItem = ((MaterialChips)sender).Text;
366+
if (SelectedItems == null)
367+
SelectedItems = new List<string>();
368+
369+
if (((MaterialChips)sender).IsSelected)
370+
SelectedItems.Add(((MaterialChips)sender).Text);
371+
else
372+
SelectedItems.Remove(((MaterialChips)sender).Text);
373+
374+
//bool hasSelected = false;
375+
//if (this.flexContainer.Children != null)
376+
//{
377+
// foreach (var item in this.flexContainer.Children)
378+
// {
379+
// if (item != null && item is MaterialChips && ((MaterialChips)item).IsSelected)
380+
// {
381+
// hasSelected = true;
382+
// break;
383+
// }
384+
// }
385+
//}
386+
387+
//if (!hasSelected)
388+
//{
389+
// ((MaterialChips)sender).IsSelected = true;
390+
//}
303391
}
304-
305-
bool hasSelected = false;
306-
if (this.stcContainer.Children != null)
392+
else
307393
{
308-
foreach (var item in this.stcContainer.Children)
394+
if (((MaterialChips)sender).IsSelected)
395+
{
396+
this.SelectedItem = ((MaterialChips)sender).Text;
397+
}
398+
399+
bool hasSelected = false;
400+
if (this.flexContainer.Children != null)
309401
{
310-
if (item != null && item is MaterialChips && ((MaterialChips)item).IsSelected)
402+
foreach (var item in this.flexContainer.Children)
311403
{
312-
hasSelected = true;
313-
break;
404+
if (item != null && item is MaterialChips && ((MaterialChips)item).IsSelected)
405+
{
406+
hasSelected = true;
407+
break;
408+
}
314409
}
315410
}
316-
}
317411

318-
if (!hasSelected)
319-
{
320-
((MaterialChips)sender).IsSelected = true;
412+
if (!hasSelected)
413+
{
414+
((MaterialChips)sender).IsSelected = true;
415+
}
321416
}
322417
}
323418
}
@@ -347,7 +442,7 @@ protected override void OnPropertyChanged([CallerMemberName] string propertyName
347442
break;
348443

349444
case nameof(this.Padding):
350-
this.stcContainer.Padding = this.Padding;
445+
this.flexContainer.Padding = this.Padding;
351446
break;
352447

353448
case nameof(this.AssistiveText):
@@ -364,10 +459,9 @@ protected override void OnPropertyChanged([CallerMemberName] string propertyName
364459
case nameof(this.AssistiveSize):
365460
this.lblAssistive.FontSize = this.AssistiveSize;
366461
break;
367-
368462
}
369463
}
370464

371465
#endregion Methods
372466
}
373-
}
467+
}

0 commit comments

Comments
 (0)