Stop and reset video when carousal swiped - Xamarin.forms - xamarin

In my xamarin.forms app I have a carousal view which have MediaElement as template. The videos are played from URL. What I am trying to achieve is when user swipe the carousal items, I want the currently playing video needs to stop and play the next video binded to that cell and when we swipe back, the previous video needs to restart. Currently the playing video will not get closed and when we swipe the next video will also get played along with it.
How can I solve this? Any help is appreciated.
Carousal View with video.
<CarouselView ItemsSource="{Binding }" >
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
<MediaElement AutoPlay="True" Aspect="AspectFill"
Source="{Binding Video}" /
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>

We can use BindingContextChanged and PositionChanged Events.
<CarouselView ItemsSource="{Binding }" PositionChanged="carouselView_PositionChanged">
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
<MediaElement AutoPlay="True" Aspect="AspectFill"
Source="{Binding Video}" BindingContextChanged="MediaElement_BindingContextChanged" />
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
In Code Behind
List<MediaElement> mediaElements = new List<MediaElement>();
private void MediaElement_BindingContextChanged(object sender, EventArgs e)
{
var element = sender as MediaElement;
mediaElements.Add(element);
}
private void carouselView_PositionChanged(object sender, PositionChangedEventArgs e)
{
mediaElements[e.PreviousPosition].Stop();
}

Related

Xamarin form carouselview scrolls with multiple items for single scroll

Iam using Carousel view control available in Xamarin form(Version 5).
In my case i used Listviews inside carousel view. It works fine if scroll by swiping to left or right, but if i programmatically set the ScrollTo or Position property for the carousel view using button click then it is scrolling multiple times though i'm setting single incremental value.
I added SnapPointsType="MandatorySingle" as mentioned here
One more issue is if my current carousel position is zero and moving to last position or more then one is not working.
<AbsoluteLayout Margin="2" BackgroundColor="Transparent">
<CarouselView
x:Name="MyCarousalView"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
Scrolled="CarouselViewScrolled">
<CarouselView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" ItemSpacing="0" SnapPointsType="MandatorySingle" />
</CarouselView.ItemsLayout>
<CarouselView.ItemTemplate>
<DataTemplate>
<ListView
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
ItemsSource="{Binding .}"
x:FieldModifier="public">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Tapped="ViewCellTapped">
<StackLayout Padding="0">
<StackLayout Padding="20,1" VerticalOptions="StartAndExpand" Spacing="0" >
<Label
FontSize="16"
Text="{Binding Description}"
FontAttributes="Bold"/>
<Label
FontSize="14"
Text="{Binding CreatedDate}" />
</StackLayout>
<Label HorizontalOptions="FillAndExpand" Padding="0" HeightRequest="1" BackgroundColor="#D4D4D4"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
</AbsoluteLayout>
Next button click event
private void NextClicked(object sender, EventArgs e)
{
MyCarousalView.ScrollTo((MyCarousalView.Position + 1) < _weekDaysList.Count ? MyCarousalView.Position + 1 : 0);
}
Carousel view binding:
List<List<Note>> _myList;
_myList=getData(); //based on service response
MyCarousalView.ItemsSource = null;
MyCarousalView.ItemsSource = _myList;
Screen recording with issue image
Screen video
Please letme know if any solution/workaround. Thanks

Xamarin Forms CollectionView Custom Layout Design

In the app that I'm designing, I use collectionview to show loads of images. And this is my current design.
And this is the design I want.
where the images that are shorter in height will have the next image fill up the white spaces.
Heres my code:
<CollectionView x:Name="cv_WallPapers"
ItemsSource="{Binding Results, Mode=TwoWay}"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
SelectionMode="Single"
SelectionChanged="cv_WallPapers_SelectionChanged"
>
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2"
VerticalItemSpacing="5"
HorizontalItemSpacing="5"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Frame Padding="4"
BorderColor="#34eba8"
BackgroundColor="#34eba8"
CornerRadius="10"
HasShadow="False">
<Image Source="{Binding urls.regular}"
HorizontalOptions="FillAndExpand"/>
</Frame>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
I've no idea how to do that in Xamarin. And appreciate the help!
Unfortunately,CollectionView in Forms still doesn't support such a layout until now .However, we could use Custom Renderer as a workaround in Android.
public class MyCollectionViewRenderer: CollectionViewRenderer
{
public MyCollectionViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<ItemsView> elementChangedEvent)
{
base.OnElementChanged(elementChangedEvent);
if(elementChangedEvent.NewElement!=null)
{
this.SetLayoutManager(new StaggeredGridLayoutManager(2, 1));
}
}
}
In iOS , because the UICollectionView in native iOS doesn't have such a property or API , so we need to implement it manually (re-calculate the size of each item and set the offset) . Which you could refer https://developer.apple.com/documentation/uikit/uicollectionview/customizing_collection_view_layouts?language=objc . And I will post the feature request as soon as possible .

Focus on entry in listview on android

So i need to allow the user to get access to each entry field within the listview to enter a value, my code runs fine on iOS but once to try it on android i cant get access to the entry box, once the entry field is tapped it will show the cursor but it will not focus on the entry field and you cannot type anything as the keyboard doesnt appear. Does anyone have any idea how to fix this issue ?
<ListView x:Name="btnlist" Margin="0,0,0,20" Grid.Row="8" Grid.Column="1" Grid.ColumnSpan="2" AutomationId="ListMed"
CachingStrategy="RecycleElement" RowHeight="65" IsPullToRefreshEnabled="False" IsVisible="false" SeparatorColor="transparent"
>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Appearing="Handle_Appearing1">
<local:XFDoneEntry x:Name="txtFrequency" Text="{Binding Count}" Day="{Binding Placeholder}" wdaynum="{Binding Wdaynum}" Placeholder="{Binding Placeholder}" Unfocused="Leave_box" VerticalOptions="Center" Keyboard="Numeric" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
//This is the code i use to find the entry boxes within the listview.
void Handle_Appearing1(object sender, System.EventArgs e)
{
var ViewcellAll1 = (ViewCell)sender;
ddoneentry = ViewcellAll1.View.FindByName<XFDoneEntry>("txtFrequency");
}
//this is the app with the listviews, depending on which days the user chooses the appropriate entry fields are populated within the second listview with entries.

Can I use C# code to add a call to a command instead of a <Grid.GestureRecognizers>?

I have this code:
<ViewCell x:Name="co">
<Grid VerticalOptions="CenterAndExpand" Padding="20, 0">
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding OpenPickerCommand}" CommandParameter="{x:Reference coPicker}" NumberOfTapsRequired="1" />
</Grid.GestureRecognizers>
<Picker x:Name="coPicker" IsVisible="false" HorizontalOptions="End" SelectedIndexChanged="coPickerSelectedIndexChanged" ItemsSource="{Binding Order}"></Picker>
<Label x:Name="coLabel" HorizontalOptions="End"/>
</Grid>
</ViewCell>
Is there a way that I can in C# connect up a command to the tapping of the cell rather than have to use the XAML <Grid.GestureRecognizers> ?
Adding a GestureRecognizer to a ViewCell is a big no-no. A ViewCell exists within a ListView or TableView which have more than enough tapped options of their own. Adding a GestureRecognizer might confuse the OS as to which tap it should handle.
Your options for the GestureRecognizer are basically the following 3, but I advise against them in a scenario where you have a ListView/TableView.
Check out some of the ListView/ViewCell based alternatives I mention below in your situation.
1. GestureRecognizer - Add it in code
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.Tapped += (s, e) => {
// handle the tap
};
myGrid.GestureRecognizers.Add(tapGestureRecognizer);
2. GestureRecognizer - Use a command
When you use MVVM you can also use a command binding in C#:
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.SetBinding (TapGestureRecognizer.CommandProperty, "TapCommand");
myGrid.GestureRecognizers.Add(tapGestureRecognizer);
Which can then be bound in XAML:
<Grid>
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}" />
</Grid.GestureRecognizers>
</Grid>
3. GestureRecognizer - Add it in XAML as you have done
<Grid>
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding OpenPickerCommand}" CommandParameter="{x:Reference coPicker}" NumberOfTapsRequired="1" />
</Grid.GestureRecognizers>
</Grid>
4. ViewCell - Tapped event
For the ViewCell you have a Tapped event:
<ViewCell Height="100" Tapped="OnTapped">
<ViewCell.View>
<StackLayout BackgroundColor="White" >
</StackLayout>
</ViewCell.View>
</ViewCell>
Which you can implement in code-behind:
void OnTapped (object sender, System.EventArgs e) { //your code}
5. ViewCell - Tapped command
When using MVVM you don't want to put a lot of business logic in the code-behind for your pages. In that case you can use a Behavior to convert the event to a command. A sample of that can be found here:
https://github.com/xamarin/xamarin-forms-samples/tree/master/Behaviors/EventToCommandBehavior/EventToCommandBehavior
6. ListView - ItemSelected
ListView itself also has an ItemSelected event. This can be handled the same way as the ViewCell Tapped event with both an event in code-behind or a Behavior to delegate it to a Command.
7. ListView - SelectedItem property
You can bind the SelectedItem to a property in your view model. On the setter you can perform your custom code.
<ListView
ItemsSource="{Binding YourItems}"
SelectedItem="{Binding YourSelectedItem, Mode=TwoWay}" >
</ListView>
And in code:
string _yourSelectedItem;
public string YourSelectedItem
{
get { return _yourSelectedItem; }
set {
_yourSelectedItem = value;
// Perform your custom functionality
}
}

MediaElement Windows Phone 8

I am displaying list of songs on listbox i have bind media element but i am Unable to get media element name instance in songs.cs file and unable to play song
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<MediaElement Name="Player" Source="{Binding SongUrl}" AutoPlay="False"/>
<Button Name="Click" Click="Play_Click" Content="Button"/>
<StackPanel Width="150" Height="50">
<TextBlock Text="{Binding SongName}" TextWrapping="Wrap" Style="{StaticResource PhoneTextSubtleStyle}" TextAlignment="Center" Foreground="Red" FontSize="16"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
example in Songs.cs:
private void Play_Click(object sender, RoutedEventArgs e)
{
Player.play(); (unable to get Media Element name)
}
The media player should not be inside the ItemTemplate since you will be playing only one sound at a time I believe (it would be costly to have a media element for eaach item). So you should move the MEdiaaPlayer outside and on button click do:
private void Play_Click(object sender, RoutedEventArgs e)
{
Button button=sender as Button;
Player.Source=((Item)button.DataContext).SongUrl
Player.play(); (unable to get Media Element name)
}

Resources