Reputation: 1142
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
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