CeeRo
CeeRo

Reputation: 1142

Xamarin.Forms Slider.Clicked event?

I'm making an mp3 player in Xamarin.Forms, in which the slider should both show time expired and allow jumping to locations in the track. As far as I can tell, only the ValueChanged event is available, with the unfortunate sideeffect that every time my timer updates the slider value, I also trigger my player.SeekTo method, causing broken playback.

Is there any way to specifically pick up touch events on a slider? If not, does anyone have any suggestions on how to make this work?

In case it's relevant, here's my code for the MainPage:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace MuZor
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            PlayButton.Clicked += PlayButton_Clicked;
            PlaylistsButton.Clicked += PlaylistsButton_Clicked;
            RandomButton.Clicked += RandomButton_Clicked;
            RepeatButton.Clicked += RepeatButton_Clicked;
            ChoiceButton.Clicked += ChoiceButton_Clicked;
            PreviousButton.Clicked += PreviousButton_Clicked;
            NextButton.Clicked += NextButton_Clicked;
            TimeSlider.ValueChanged += TimeSlider_ValueChanged;

            MessagingCenter.Subscribe<Interfaces.IAudioPlayer>(App.player, "PlayerPrepared", (args) =>
            {
                System.Diagnostics.Debug.WriteLine("Message received");
                PlayerPrepared();
            });
        }

        private void TimeSlider_ValueChanged(object sender, ValueChangedEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Slider value changed, value = " + e.NewValue + "(int = " + (int)e.NewValue);
            //App.player.SeekTo((int)e.NewValue);
        }

        private void NextButton_Clicked(object sender, EventArgs e)
        {
            if (!App.settings.RandomOn && App.settings.CurrentTrack < App.playlist.Count - 1)
            {
                Play((int)App.settings.CurrentTrack + 1);
            }
        }

        private void PreviousButton_Clicked(object sender, EventArgs e)
        {
            if (!App.settings.RandomOn && App.settings.CurrentTrack > 0)
            {
                Play((int)App.settings.CurrentTrack - 1);
            }
        }

        private void ChoiceButton_Clicked(object sender, EventArgs e)
        {
        }

        private void RepeatButton_Clicked(object sender, EventArgs e)
        {
        }

        private void RandomButton_Clicked(object sender, EventArgs e)
        {
        }

        private void PlaylistsButton_Clicked(object sender, EventArgs e)
        {
        }

        private void PlayButton_Clicked(object sender, EventArgs e)
        {
            if (App.settings.IsPaused || App.player.IsPlaying())
            {
                App.player.PauseResume();
                if (App.settings.IsPaused)
                {
                    UnPause();
                }
                else
                {
                    Pause();
                }
            }
            else
            {
                int trackToplay = App.settings.CurrentTrack != null ? (int)App.settings.CurrentTrack : 0;
                Play(trackToplay);
            }
        }

        private void Play(int currentTrack)
        {
            HelperClasses.SettingsHelper.SaveCurrentTrack(currentTrack);
            App.player.LoadAndPlay(App.playlist[currentTrack].Path);
        }

        private void Pause()
        {
            HelperClasses.SettingsHelper.SavePausedState(true);
            Device.BeginInvokeOnMainThread(() =>
            {
                PlayButton.Text = "Play";
            });
        }

        private void UnPause()
        {
            HelperClasses.SettingsHelper.SavePausedState(false);
            Device.BeginInvokeOnMainThread(() =>
            {
                PlayButton.Text = "Pause";
            });
            StartTimer();
        }

        private void StartTimer()
        {
            double position;
            Device.StartTimer(new TimeSpan(0, 0, 1), () =>
            {
                position = App.player.GetCurrentPosition();
                TimeSpan runTime = TimeSpan.FromMilliseconds(position);
                Device.BeginInvokeOnMainThread(() =>
                {
                    TimeLabel.Text = runTime.ToString(@"mm\:ss");
                    TimeSlider.Value = position;
                });
                if (App.player.IsPlaying())
                    return true;
                else
                    return false;
            });
        }

        private void PlayerPrepared()
        {
            var totalDurationInMS = App.player.GetDuration();
            TimeSlider.Maximum = totalDurationInMS;
            TimeSlider.Minimum = 0;
            TimeSpan totalDuration = TimeSpan.FromMilliseconds(totalDurationInMS);
            Device.BeginInvokeOnMainThread(() =>
            {
                RemainingTimeLabel.Text = totalDuration.ToString(@"mm\:ss");
                TimeLabel.Text = "00:00";
            });
            UnPause();
        }
    }
}

Upvotes: 1

Views: 667

Answers (1)

CeeRo
CeeRo

Reputation: 1142

I think I've found a workaround. Since the valuechanged event contains both old and new values, I'll only fire SeekTo if the difference is negative or bigger than 2.

Upvotes: 1

Related Questions