Forum Xamarin.Forms

Can you limit a Slider to only allow integer values? (Hopefully snapping to the next integer)

JKayJKay USMember ✭✭✭

I have a slider I would like to use as a rating feature. I would like the slider to be between 0-5 but only allow integer values. and preferably snap to the next integer. Is this possible?

Posts

  • JKayJKay USMember ✭✭✭

    Absolutely Brilliant! Thank you

  • MitchMilamMitchMilam USMember ✭✭✭

    You bet. And beer is accepted as payment...

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭
    edited June 2015

    @MitchMilam I tried to use your ExtendedSlider and it seemed to work on the first try. Then I tried to set the StepValue to 0.01 and then it crashes my app. When I use a StepValue of 0.1 it works but it's laggy.
    But it only happens on Android on iOS however it works perfect.

    Then I created a little Test-App and tried it again and it worked. But in the Test-App there is only one StackLayout so I thought that maybe this is a problem when the ExtendedSlider is in nested Layouts.
    In my App the Control is nested like this: RelativeLayout -> Frame -> StackLayout -> ExtendedSlider

    What could be the problem here?

    What happens is that GC goes mad. This is what happens on the debug output:

    06-11 12:04:39.122 D/Mono    (30322): Assembly Ref addref XLabs.Forms.Droid[0x710a9ac0] -> Xamarin.Forms.Core[0x710d1f60]: 11
    06-11 12:04:40.149 I/dalvikvm(30322): Could not find method android.widget.EditText.<init>, referenced from method md5530bd51e982e6e7b340b73e88efe666e.EntryEditText.<init>
    06-11 12:04:40.150 W/dalvikvm(30322): VFY: unable to resolve direct method 9458: Landroid/widget/EditText;.<init> (Landroid/content/Context;Landroid/util/AttributeSet;II)V
    06-11 12:04:40.151 D/dalvikvm(30322): VFY: replacing opcode 0x70 at 0x0000
    06-11 12:04:42.275 D/Mono    (30322): Assembly Ref addref XLabs.Forms[0x710d4610] -> System.Runtime.Extensions[0x773a62e0]: 4
    06-11 12:04:45.835 D/dalvikvm(30322): GC_EXPLICIT freed 242K, 8% free 17471K/18804K, paused 2ms+3ms, total 26ms
    06-11 12:04:45.849 D/Mono    (30322): GC_OLD_BRIDGE num-objects 318 num_hash_entries 329 sccs size 329 init 0.00ms df1 0.84ms sort 0.09ms dfs2 0.67ms setup-cb 0.26ms free-data 0.43ms links 13/13/13/1 dfs passes 660/342
    06-11 12:04:45.852 D/Mono    (30322): GC_MINOR: (Nursery full) pause 26.65ms, total 26.80ms, bridge 47.97ms promoted 1392K major 1840K los 13814K
    06-11 12:04:47.836 D/Mono    (30322): GC_OLD_BRIDGE num-objects 318 num_hash_entries 329 sccs size 329 init 0.00ms df1 0.84ms sort 0.09ms dfs2 0.67ms setup-cb 0.26ms free-data 0.43ms links 0/0/0/0 dfs passes 0/0
    06-11 12:04:47.840 D/Mono    (30322): GC_MINOR: (Nursery full) pause 11.83ms, total 12.02ms, bridge 4.31ms promoted 16K major 1856K los 13814K
    06-11 12:04:49.577 D/Mono    (30322): GC_OLD_BRIDGE num-objects 318 num_hash_entries 329 sccs size 329 init 0.00ms df1 0.84ms sort 0.09ms dfs2 0.67ms setup-cb 0.26ms free-data 0.43ms links 0/0/0/0 dfs passes 0/0
    06-11 12:04:49.582 D/Mono    (30322): GC_MINOR: (Nursery full) pause 9.87ms, total 10.07ms, bridge 4.31ms promoted 32K major 1888K los 13814K
    06-11 12:04:51.247 D/Mono    (30322): GC_OLD_BRIDGE num-objects 318 num_hash_entries 329 sccs size 329 init 0.00ms df1 0.84ms sort 0.09ms dfs2 0.67ms setup-cb 0.26ms free-data 0.43ms links 0/0/0/0 dfs passes 0/0
    06-11 12:04:51.252 D/Mono    (30322): GC_MINOR: (Nursery full) pause 11.11ms, total 11.31ms, bridge 4.37ms promoted 16K major 1904K los 13814K
    06-11 12:04:51.604 I/dalvikvm(30322): threadid=4: reacting to signal 3
    06-11 12:04:51.674 I/dalvikvm(30322): Wrote stack traces to '/data/anr/traces.txt'
    06-11 12:04:53.494 D/Mono    (30322): GC_OLD_BRIDGE num-objects 318 num_hash_entries 329 sccs size 329 init 0.00ms df1 0.84ms sort 0.09ms dfs2 0.67ms setup-cb 0.26ms free-data 0.43ms links 0/0/0/0 dfs passes 0/0
    06-11 12:04:53.495 D/Mono    (30322): GC_MINOR: (Nursery full) pause 10.16ms, total 10.35ms, bridge 0.97ms promoted 32K major 1936K los 13814K
    06-11 12:04:55.389 D/Mono    (30322): GC_OLD_BRIDGE num-objects 318 num_hash_entries 329 sccs size 329 init 0.00ms df1 0.84ms sort 0.09ms dfs2 0.67ms setup-cb 0.26ms free-data 0.43ms links 0/0/0/0 dfs passes 0/0
    06-11 12:04:55.391 D/Mono    (30322): GC_MINOR: (Nursery full) pause 17.43ms, total 17.73ms, bridge 1.67ms promoted 16K major 1952K los 13814K
    06-11 12:04:57.145 D/Mono    (30322): GC_OLD_BRIDGE num-objects 318 num_hash_entries 329 sccs size 329 init 0.00ms df1 0.84ms sort 0.09ms dfs2 0.67ms setup-cb 0.26ms free-data 0.43ms links 0/0/0/0 dfs passes 0/0
    06-11 12:04:57.149 D/Mono    (30322): GC_MINOR: (Nursery full) pause 20.64ms, total 20.88ms, bridge 3.56ms promoted 16K major 1968K los 13814K
    06-11 12:04:58.906 D/Mono    (30322): GC_OLD_BRIDGE num-objects 318 num_hash_entries 329 sccs size 329 init 0.00ms df1 0.84ms sort 0.09ms dfs2 0.67ms setup-cb 0.26ms free-data 0.43ms links 0/0/0/0 dfs passes 0/0
    06-11 12:04:58.910 D/Mono    (30322): GC_MINOR: (Nursery full) pause 10.75ms, total 11.01ms, bridge 4.38ms promoted 32K major 2000K los 13814K
    

    I created a own class. And I tried the ExtendedSlider form Xlabs

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    //Edit:
    Sorry for double post I had to attach the test project.

    Ok, I investigated this more deeply. In my attached test project it works perfect with the nested control, but only when the code looks like this:

    var sliderMain = new ExtendedSlider
    {
        Minimum = 0.0f,
        Maximum = 5.0f,
        Value = 0.0f,
        StepValue = 0.01f
        HorizontalOptions = LayoutOptions.FillAndExpand
    };
    

    if you alter it to this it crashes:

    var sliderMain = new ExtendedSlider
    {
        Minimum = 0,
        Maximum = 5,
        Value = 0,
        StepValue = 0.01
        HorizontalOptions = LayoutOptions.FillAndExpand
    };
    

    However in my other app it hungs up emediatly when I press on the slider.

    06-11 12:31:56.651 D/Mono    (19528): Assembly Ref addref XLabs.Forms.Droid[0x6aeff760] -> System[0x8068f160]: 13
    06-11 12:31:56.651 D/Mono    (19528): Assembly Ref addref XLabs.Forms.Droid[0x6aeff760] -> Xamarin.Forms.Core[0x6aeff2e0]: 10
    06-11 12:31:56.656 W/art     (19528): JNI RegisterNativeMethods: attempt to register 0 native methods for md50af85d46f9bd85eaa13076bff15d9a6f.ImageButtonRenderer
    06-11 12:32:03.711 D/Mono    (19528): Assembly Ref addref XLabs.Forms[0x6aeff6a0] -> System.Runtime.Extensions[0x67575280]: 3
    06-11 12:32:04.081 I/art     (19528): Explicit concurrent mark sweep GC freed 14412(765KB) AllocSpace objects, 0(0B) LOS objects, 40% free, 19MB/33MB, paused 915us total 25.774ms
    06-11 12:32:04.081 D/Mono    (19528): GC_OLD_BRIDGE num-objects 106 num_hash_entries 137 sccs size 137 init 0.00ms df1 0.22ms sort 0.10ms dfs2 0.45ms setup-cb 0.03ms free-data 0.12ms links 44/44/65/3 dfs passes 287/181
    06-11 12:32:04.081 D/Mono    (19528): GC_MINOR: (Nursery full) pause 11.76ms, total 11.90ms, bridge 28.51ms promoted 1120K major 1552K los 13856K
    06-11 12:32:05.266 D/Mono    (19528): GC_OLD_BRIDGE num-objects 106 num_hash_entries 137 sccs size 137 init 0.00ms df1 0.22ms sort 0.10ms dfs2 0.45ms setup-cb 0.03ms free-data 0.12ms links 0/0/0/0 dfs passes 0/0
    06-11 12:32:05.266 D/Mono    (19528): GC_MINOR: (Nursery full) pause 4.02ms, total 4.09ms, bridge 0.10ms promoted 48K major 1600K los 13856K
    06-11 12:32:06.391 D/Mono    (19528): GC_OLD_BRIDGE num-objects 106 num_hash_entries 137 sccs size 137 init 0.00ms df1 0.22ms sort 0.10ms dfs2 0.45ms setup-cb 0.03ms free-data 0.12ms links 0/0/0/0 dfs passes 0/0
    06-11 12:32:06.391 D/Mono    (19528): GC_MINOR: (Nursery full) pause 4.34ms, total 4.42ms, bridge 0.43ms promoted 64K major 1664K los 13856K
    
  • MitchMilamMitchMilam USMember ✭✭✭

    @RaphaelSchindler I have a suspicion that it is because you are using the wrong values for the number. The numbers you are specifying are integers while the control takes a floating point number.

    I am also a little confused by something. The control is used to "snap" to the next integer value but you are using a non-integer value which is not how it was designed and I can't actually tell you if it will work successfully. If this is your intention, then why are you using the this control instead of the native version without the "snap" part?

    The source for that control is 100% forms-based so there are no custom renderers. I would suggest you copy the source from the XLabs project and modify the "snap" calculation to handle the interval that you require rather that try and make the control do something it was not designed to do.

  • RaphaelSchindlerRaphaelSchindler USMember ✭✭✭

    @MitchMilam Uhh I actually tried to overkill this. Everything I need in the ValueChanged event is this:

    ((Slider)sender).Value = Math.Round(valueChangedEventArgs.newValue, 2);

    But the same error appears even on the normal Slider control provided with Forms

  • Thanks a million Raphael...your ValueChanged event has solved my issue

  • EBatikEBatik NLMember ✭✭✭

    @MitchMilam any clue why i have a System.ArgumentException: Value was an invalid value for Minimum

    Parameter name: value if i set the minimun = 1.0f;

  • bleroblero MKMember

    @JKay said:
    Absolutely Brilliant! Thank you

    Just use: ((Slider)sender).Value = (int)e.NewValue;

  • MichelMoorlagMichelMoorlag USMember ✭✭

    The rangeslider can be bound to an integer and has a stepvalue property you can set. The only problem is that it does not work correct on ios in the detail of a master detail page.

  • ShimmyWeitzhandlerShimmyWeitzhandler USMember ✭✭✭
    edited November 2017

    @EBatik said:
    @MitchMilam any clue why i have a System.ArgumentException: Value was an invalid value for Minimum

    Set the Maximum property before the Minimum, that will prevent the validation from failing, thus eliminating your problem.

  • HobbeHobbe Member ✭✭

    I had a similar problem and needed a more general solution. My case is that I am porting a UWP project to Xamarin, and the project is huge, like 160.000 lines of code, and has lots of Sliders. So, putting this solution in all event handlers was not an option. Instead, I override the Xamarin.Forms.Slider. This way I could also reinstate a Tag, that was also needed. Another thing this fixes is that the arrow keys on the keyboard triggers one step change each keypress, not only after a number of key presses. This is my inherited class:

    public class Slider : Xamarin.Forms.Slider
    {
        public String Name { get; set; }
        public Object Tag { get; set; }
        public Double StepFrequency { get; set; }
        public new Double Value { get { return AdjustForStepFrequency(); } set { SetValue(value); } }
    
        private Double currentValue = 0;
    
        public Slider()
        {
        // Put in any standard settings here:
            MinimumWidthRequest = 1;
            WidthRequest = 10;
    
        // Initiate step frequency and value:
            StepFrequency = 1;
            Value = 0;
        }
    
        private void SetValue(Double value)
        {
        // Store value and update slider:
            currentValue = value;
            SetValue(ValueProperty, currentValue);
        }
    
        private Double AdjustForStepFrequency()
        {
        // Get slider value:
            Double value = (Double)GetValue(ValueProperty);
    
        // Compare new value to previous value:
            if (value > currentValue)
            {
            // Increase value by StepFrequency:
                currentValue += StepFrequency;
    
            // Update slider:
                SetValue(ValueProperty, currentValue);
            }
            else if (value < currentValue)
            {
            // Decrease value by StepFrequency:
                currentValue -= StepFrequency;
    
            // Update slider:
                SetValue(ValueProperty, currentValue);
            }
            return currentValue;
        }
    }
    
  • HobbeHobbe Member ✭✭

    Sorry, but just notices a flaw in my solution above. If the value is fetched from the slider more than once, it starts to loop because it triggers the property again. However, it works fine if the value is only moved to a local variable, and all uses is then only referring to that local value (which leaves me with a lot of code checking and changing…).

  • celopezcelopez Member ✭✭
    edited January 2020

    Using XAML you can do something like this...

    <Label BindingContext="{x:Reference cols_cats}" Text="{Binding Value, StringFormat='{0:0}'}" FontSize="Large" />
    
    <Slider x:Name="cols_cats" Maximum="10" Minimum="1" Value="5"/>
    
Sign In or Register to comment.