Issue
I have two CollectionViews in my ContentPage inside a StackLayout, one above the other. Each binds to a separate ItemsSource. Above each one I have a Label. At this point each one take up 50% of the screen and scrolls separately.
I would like everything to scroll as though it were one long list.
So I surrounded everything with a ScrollView. But then, depending on where you put your finger, the scroll may scroll the entire page (which is what I want) or just the current CollectionView.
It seems like there is no way to cancel the scroll capability of the CollectionView. Is that true? and if not, How should I set up my ContentPage ?
In the below example both CollectionViews have the same model and binding but in reality they will be different.
Here is the xaml:
<RefreshView
x:DataType="local:AllRestaurantsViewModel"
Command="{Binding LoadItemsCommand}"
IsRefreshing="{Binding IsBusy, Mode=TwoWay}">
<ScrollView>
<StackLayout>
<Label
FontSize="Large"
HorizontalOptions="Center"
Text="Suggested Restaurants" />
<CollectionView
x:Name="ItemsListView"
ItemsSource="{Binding SuggestedRestsComments}"
SelectionMode="None">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10" x:DataType="model:SuggestedRestsComment">
<Label
FontSize="16"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
Text="{Binding restaurantName}" />
<Label
FontSize="13"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemDetailTextStyle}"
Text="{Binding CityName}" />
<StackLayout.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Source={RelativeSource AncestorType={x:Type local:ItemsViewModel}}, Path=ItemTapped}"
CommandParameter="{Binding .}"
NumberOfTapsRequired="1" />
</StackLayout.GestureRecognizers>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Label
FontSize="Large"
HorizontalOptions="Center"
Text="Existing Restaurants" />
<CollectionView
x:Name="ItemsListView2"
ItemsSource="{Binding SuggestedRestsComments}"
SelectionMode="None">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10" x:DataType="model:SuggestedRestsComment">
<Label
FontSize="16"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
Text="{Binding restaurantName}" />
<Label
FontSize="13"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemDetailTextStyle}"
Text="{Binding CityName}" />
<StackLayout.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Source={RelativeSource AncestorType={x:Type local:ItemsViewModel}}, Path=ItemTapped}"
CommandParameter="{Binding .}"
NumberOfTapsRequired="1" />
</StackLayout.GestureRecognizers>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ScrollView>
</RefreshView>
Solution
You could have a try with Custom CollectionViewRenderer to achieve that in each platform.
For example, send a mesage in Forms:
void OnButtonClicked(object sender, EventArgs e)
{
MessagingCenter.Send<object>(this, "StopScrollinng");
}
Then in iOS CustomCollectionViewRenderer
class stop scrolling:
public class CustomCollectionViewRenderer: CollectionViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<GroupableItemsView> e)
{
base.OnElementChanged(e);
MessagingCenter.Subscribe<object>(this, "StopScrollinng", (sender) =>
{
// Do something whenever the "StopScrollinng" message is received
if (Control != null)
{
NSArray s = Control.ValueForKey(new NSString("_subviewCache")) as NSMutableArray;
UICollectionView c = s.GetItem<UICollectionView>(0);
c.SetContentOffset(c.ContentOffset, true);
}
});
}
}
And in Android CustomCollectionViewRenderer
class stop scrolling:
public class CustomCollectionViewRenderer: CollectionViewRenderer
{
public CustomCollectionViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<ItemsView> elementChangedEvent)
{
base.OnElementChanged(elementChangedEvent);
MessagingCenter.Subscribe<object>(this, "StopScrollinng", (sender) =>
{
// Do something whenever the "StopScrollinng" message is received
this.DispatchTouchEvent(MotionEvent.Obtain(SystemClock.UptimeMillis(), SystemClock.UptimeMillis(), MotionEventActions.Cancel, 0, 0, 0));
});
}
}
Answered By - Junior Jiang
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.