I have a implement syncfusion Carousel and binding items using ItemTemplate.When i load the items to Carousel all item appears in Carousel view.But i need to add a doted indicator for it.
When user swipe though the Carousel by the dots should indicate current position.
When reading from documentation of syncfusion rotator have this functionality.
I need to add this to carousel view.
Here you can find all the SfCarousel Class Members.
And there's no property for the dots you refered in the SfCarousel print.
In fact, I think you are confusing it with another component called SfRotator. (that has an identical example like your print). and the property you are looking for is called: DotPlacement.
And can have the following states:
None //No Dots
Default //Dots Inside the Rotator View
OutSide //Dots Outside the Rotator View
We have analyzed your query and currently we don’t have dots view support in CarouselView. However, we can fulfill this requirement by using Border or Button control as like below code snippet.
Custom DotsView:
XAML:
<border:SfBorder BorderColor="{Binding ThumbBorder}" HorizontalOptions="Center" VerticalOptions="Center" BorderWidth="5" CornerRadius="50" />
Carousel View:
XAML:
<carousel:SfCarousel x:Name="carousel" Grid.Row="0" Offset="0" ItemsSource="{Binding ImageCollection}" ItemTemplate="{StaticResource itemTemplate}"
ItemHeight="200" SelectionChanged="Carousel_SelectionChanged"
ItemWidth="200" />
<StackLayout Grid.Row="1" HorizontalOptions="Center" x:Name="rotatorThumb" BackgroundColor="Transparent" Orientation="Horizontal"/>
C#:
public MainPage()
{
InitializeComponent();
Command command = new Command((object thumb) =>
{
var thumbView = thumb as DotsView;
if (thumbView != null)
{
((rotatorThumb.Children[carousel.SelectedIndex] as DotsView).BindingContext as CarouselModel).
ThumbBorder = Color.LightGray;
carousel.SelectedIndex = thumbView.Index;
(thumbView.BindingContext as CarouselModel).ThumbBorder = Color.Red;
}
});
for (var i = 0; i < ImageCollection.Count; i++)
{
var itemView = new DotsView() { BindingContext = ImageCollection[i], Index = i };
if (carousel.SelectedIndex == i)
(itemView.BindingContext as CarouselModel).ThumbBorder = Color.Red;
TapGestureRecognizer thumbTap = new TapGestureRecognizer();
thumbTap.Command = command;
itemView.GestureRecognizers.Add(thumbTap);
thumbTap.CommandParameter = itemView;
rotatorThumb.Children.Add(itemView);
}
}
Output:
Sample
Related
I have a xamarin.forms app in which I am trying achieve a specific UI.Please find the attched image.
.
As you can see It is a list view and have a breadcrumbs below it. What I am trying to achieve is when user click any of the other items such as "stores" or "users" in breadcrumbs, then the upper layout horizontally slide and show another list view.Where I am stuck is I want to fix the breadcrumbs at the bottom and the change only needs the upper layout i.e.; the list view layout. How can I achieve this. Any ideas will be much helpfull.
What I am thinking is putting four listview inside horizontal scroll view.But is it the better approach?
This could be achieved by simple Translate animation.
A simple implementation of the idea of using translation. Change as per need.
XAML layout:
<StackLayout>
<Grid x:Name="rotatingView">
<ListView
...../>
<ListView
TranslationX="{Binding Width, Source={x:Reference rotatingView}}"
...../>
<ListView
TranslationX="{Binding Width, Source={x:Reference rotatingView}}"
...../>
<ListView
TranslationX="{Binding Width, Source={x:Reference rotatingView}}"
...../>
</Grid>
<Button
Text="0"
Clicked="Button_Clicked"/>
<Button
Text="1"
Clicked="Button_Clicked"/>
<Button
Text="2"
Clicked="Button_Clicked"/>
<Button
Text="3"
Clicked="Button_Clicked"/>
</StackLayout>
Xaml.cs clicked:
int previousSelectedIndex = 0;
private async void Button_Clicked(System.Object sender, System.EventArgs e)
{
Button selectedtab = (sender as Button);
int selectedViewIndex = int.Parse(selectedtab.Text);
VisualElement previousView = rotatingView.Children[previousSelectedIndex];
VisualElement selectedView = rotatingView.Children[selectedViewIndex];
bool isMovingForward = true;
if (previousSelectedIndex < selectedViewIndex)
{
isMovingForward = true;
}
else if(previousSelectedIndex > selectedViewIndex)
{
isMovingForward = false;
}
if (selectedViewIndex != previousSelectedIndex)
{
selectedView.TranslationX = rotatingView.Width * (isMovingForward ? 1 : -1);
await Task.WhenAll(
selectedView.TranslateTo(0, 0),
previousView.TranslateTo(rotatingView.Width * (isMovingForward ? -1 : 1), 0));
}
this.previousSelectedIndex = selectedViewIndex;
}
Here I have used the text of buttons to select index of the view. Hope this could help.
if you are looking for a breadcrumb navigation control.
I have created a control that will generate one automatically, and it's highly customisable.
https://github.com/IeuanWalker/Xamarin.Forms.Breadcrumb
I have a StackLayout and a number of elements inside (buttons, texts etc).
I want the ActivityIndicator to overlay the entire screen and make it not able to do anything to those elements.
I have put ActivityIndicator inside the StackLayout but wrapped it with AbsoluteLayout thinking that AbsoluteLayout can easitly overlap everything:
<StackLayout>
<AbsoluteLayout>
<ActivityIndicator ... />
</AbsoluteLayout>
<...other elements...>
</StackLayout>
Instead activity indicator is displayed at the top of the StackLayout and other elements are available for affecting. I'm new in Xamarin and layouts, what am I doing wrong? All samples in the Internet have single ActivityIndicator per page...
It is better said that an AbsoluteLayout's children can easily overlap each other. Just as a StackLayout lets you stack controls inside , vertically or horizontally, an AbsoluteLayout lets you position controls inside using absolute or proportional values, thus if two controls have the same absolute positioning set, they will overlap 100%.
Therefore, you want to wrap your StackLayout and another StackLayout that has your ActivityIndicator inside an AbsoluteLayout using proportional sizing, e.g:
<AbsoluteLayout>
<StackLayout
x:Name="mainLayout"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All" >
<Label Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text="Do Something"
Clicked="DoSomethingBtn_Clicked" />
</StackLayout>
<StackLayout
x:Name="aiLayout"
IsVisible="False"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
BackgroundColor="Gray" Opacity="0.5">
<ActivityIndicator
x:Name="ai"
IsRunning="False"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
Color="Black"/>
</StackLayout>
</AbsoluteLayout>
The above sets the two StackLayouts to both take up the full size of the parent container of the AbsoluteLayout, which is presumably a Page. The StackLayout that has the indicator is initially hidden. IN the page code behind for the above example, I show the second StackLayout and start the activity indicator and show it for 2 seconds, and then hide it again:
private async void DoSomethingBtn_Clicked(object sender, EventArgs e)
{
ai.IsRunning = true;
aiLayout.IsVisible = true;
await Task.Delay(2000);
aiLayout.IsVisible = false;
ai.IsRunning = false;
}
Here is what it looks like:
And since the second StackLayout completely covers the first, none of the controls in the first StackLayout are clickable.
Might be worth going over the docs for the AbsoluteLayout to understand the AbsoluteLayout.LayoutBounds and AbsoluteLayout.LayoutFlags:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/layouts/absolute-layout
If you want to "overlap", you need to be outside of the StackLayout. A Grid is the most common control for this:
<Grid>
<StackLayout>
<...other elements...>
</StackLayout>
<ActivityIndicator ... />
</Grid>
Here's a hacked-up control for making things full-screen via the horribly-named RelativeLayout (tested in Android only)
[ContentProperty("ContentInner")]
public class FullScreenLayout : ContentView
{
public View ContentInner
{
get => ((RelativeLayout) Content).Children[0];
set
{
var display = DeviceDisplay.MainDisplayInfo;
var screenWidth = display.Width / display.Density;
var screenHeight = display.Height / display.Density;
var wrapper = new RelativeLayout();
wrapper.Children.Add(value, () => new Rectangle(0, 0, screenWidth, screenHeight));
Content = wrapper;
}
}
}
It can be used like this:
<controls:FullScreenLayout>
<!-- Anything you want fullscreen here -->
</controls:FullScreenLayout>
Unfortunately, if you use NavigationPage, this won't overlap the navigation bar. Every other solution currently on this page has the same issue. According to this question, it's not possible to solve this without using platform-specific customer renderers. Ugh.
If you don't mind the page being dimmed, you can use Rg.Plugins.Popup which implements the custom renderers needed.
I ended up solving my similar problem (dimming most of the screen) by implementing a custom renderer for the navigation page itself.
I have some XAML code that looks like this. It names four grids and then in the back end my C# does something based on the values. As I can not have duplicate names I created four names.
But I would like to simplify the back-end code so is it possible that I could bind back the value of the height from my XAML > ViewModel and then check that value in my C#
<Grid IsVisible="{Binding AVisible}" VerticalOptions="FillAndExpand">
<Grid x:Name="aWords" VerticalOptions="FillAndExpand" >
<Frame VerticalOptions="FillAndExpand">
<Frame.Content>
<Grid x:Name="aArea" VerticalOptions="CenterAndExpand">
<Label Text="{Binding Detail}"
</Grid>
</Frame.Content>
</Frame>
</Grid>
</Grid>
<Grid IsVisible="{Binding BVisible}" VerticalOptions="FillAndExpand">
<Grid x:Name="bWords" VerticalOptions="FillAndExpand" >
<Frame VerticalOptions="FillAndExpand">
<Frame.Content>
<Grid x:Name="bArea" VerticalOptions="CenterAndExpand">
<Label Text="{Binding Detail}"
</Grid>
</Frame.Content>
</Frame>
</Grid>
</Grid>
and in C#
var a = aWords.Height;
var b = aArea.Height;
if (b > a) doSomething();
var c = aWords.Height;
var d = aArea.Height;
if (d > c) doSomething();
What I would like to do is like this:
if (vm.AreaHeight > vm.WordsHeight) doSomething();
The way you can pass those values to your ViewModel is by using the binding context of your page for interacting with the ViewModel methods and properties.
First, create a couple of properties in your ViewModel to hold the Height of your objects: i.e.:
public int AreaHeight { get; set; }
public int WordsHeight { get; set; }
Then, on your page override the event: OnAppearing() in order to get the Height from your grids using the x:Name attribute, then you will call from your ViewModel the method: doSomething() passing the obtained values as parameters. i.e.:
protected override void OnAppearing()
{
base.OnAppearing();
// Get your height from your grids here ...
// int gridAHeight = aWords.Height;
// int gridBHeight = aArea.Height;
(BindingContext as YourViewModel).doSomething(gridAHeight, gridBHeight);
}
Finally, in your ViewModel, implement the method doSomething() and catch the parameters obtained from the view page by assigning them to your previously created properties. i.e:
public void DoSomething(int gridAHeight, int gridBHeight)
{
AreaHeight = gridAHeight;
WordsHeight = gridBHeight;
if (AreaHeight < WordsHeight)
{
// place your logic here...
}
}
That is all you need. It is just basic MVVM pattern.
Passing heights or binding heights to a ViewModel violates MVVM pattern. ViewModels shouldn't know anything about a specific view.
I would suggest refactoring your view and finding a different layout depending on the specifics needed for the page. A possible solution would be to use a ListView with labels and restricting the content in the ObservableCollection so you don't have duplicates.
If you have to have it set up that way, I would suggest using MaxLines and/or LineBreakMode to restrict the height of your Labels.
Issues with doing logic based on height:
FontSize could be different based on AccessibilitySettings specified in the users phone
Rotating the screen will change how much of the label is wrapped due to the label expanding. This would force you to do a recalculation again.
Basically, you can't. There isn't the height in XAML, but rather HeightRequest. The layout is a complex thing and the height may not end up being what is your HeightRequest, it is just a suggested value. So you can only change that suggested value from the view model that is not the problem, but that is not what you asked for.
I am trying to create a custom component in Nativescript. The component works fine with the static data, I want to add some custom properties to that control, but the are not accessible in the code behind. I am trying to create a MCQ like box or a something similar to radio control, so user can only select one option from the given ones.
CustomControl.xml
<StackLayout orientation="vertical" class="form" loaded="loaded">
<Repeater items="{{ items }}">
<Repeater.itemTemplate>
<StackLayout orientation="vertical" tap="itemTapped" id="{{id}}">
<StackLayout orientation="horizontal" verticalAlignment="center">
<Label text="{{text}}" class="form-field" width="88%"/>
<Label text="{{characterCode}}" visibility="{{visible ? 'visible' : 'collapsed'}}" class="icon"/>
</StackLayout>
<StackLayout class="separator"/>
</StackLayout>
</Repeater.itemTemplate>
</Repeater>
</StackLayout>
CustomControl.js
var Observable = require("data/observable").Observable;
var ObservableArray = require("data/observable-array").ObservableArray;
var _component;
var _viewModel = new Observable();
var _selectedId = null;
exports.loaded = function(args){
_component = args.object;
//passing in _component.items as array throws undefined
var items = getInitializedArray(["Some text","Someother text"]);
_viewModel.set("items", items);
_component.bindingContext = _viewModel;
}
exports.itemTapped = function(args){
var id = args.object.id;
if(_selectedId === null){
var item = _viewModel.get("items").getItem(id);
item.visible = true;
_viewModel.get("items").setItem(item, id);
}else{
var item = _viewModel.get("items").getItem(_selectedId);
item.visible = false;
item = _viewModel.get("items").getItem(id);
item.visible = true;
_viewModel.get("items").setItem(item, id);
}
_selectedId = id;
}
function getInitializedArray(data){
var id=0;
var items = data.map((listItem) => {
return {
text: listItem,
characterCode: String.fromCharCode(0xea11),
visible: false,
id: id++
}
});
return new ObservableArray(items);
}
Trying to use it in my page as
<CustomComponents:CustomControl items="{{items}}"/>
But using args.object.items throws undefined property for object.
I have read that I'll have to use dependency-observable and will have to create a plugin. But I am not using any platform specific thing, I am just creating a component with existing ui components and its pretty simple what I want to achieve. Is there a way to bind custom properties? Plugins are too complex for this, How can I achieve it?
After reading the docs and going through various forums and github issues following is what I have found and thanks to Nick lliev' comment.
To give custom properties to your controls you'll have to use the code only technique, I have written a blog http://mobile.folio3.com/creating-custom-controls-in-nativescript/ describing both the techniques showing how to give custom properties to your custom controls.
Is there any way we can create Carousel View instead of Carousel page so that only portion of the page swipes left or right. Also I want to create this control in the Xamarin Forms and not specific to platform.
If we need to create this custom control in the xamarin.android or xamarin.iOS then what is the real benefits of using the Xamarin.forms where this simple requirements are not getting satisfied.
There's a well documented CarouselView project hosted on github:
https://github.com/chrisriesgo/xamarin-forms-carouselview
and
http://chrisriesgo.com/xamarin-forms-carousel-view-recipe/
The nuget package for the CarouselView is now available (v2.3.0-pre1):
https://www.nuget.org/packages/Xamarin.Forms.CarouselView/2.3.0-pre1
We can use the CarouselView which was introduced in Xamarin forms 4.3. Now in Xamarin 4.6, we don't have to use the Forms.SetFlags("CollectionView_Experimental"); in appdelegate of iOS and mainactivity of android.
However, to use the indicatorview for the Carousel page we have to set this
Forms.SetFlags("IndicatorView_Experimental"); in appdelegate of iOS and mainactivity of android.
I have just implemented a similar thing. To create the a carousel view, I just created a horizontal Stacklayout, wrapped in a horizontal scroll view.
In my particular example, I needed to create an image gallery. I used the Camera control from the Xamarin.Labs project to get the image from either the camera roll or the camera itself. I then added this as a child to the Stacklayout.
Hope this helps.
As of Xamarin.Forms V2.2.0-pre1 CarouselView has now been added to Xamarin.Forms.
CarouselView
CarouselView is intended to fully replace CarouselPage. CarouselPage
will be deprecated in a future release. CarouselView is superior in
many ways, including its ability to be virtualized and nested within
layouts.
See https://forums.xamarin.com/discussion/63983/xamarin-forms-2-2-0-pre1-released#latest
Unfortunately there is no documentation on this as of yet.
EDIT:
CarouselView was Removed for Xamarin.Forms V2.2.0.31 because it wasn't ready for stable release. But from the look of it it will be merged back soon.
For now you can find the seperate CarouselView nuget package here: https://www.nuget.org/packages/Xamarin.Forms.CarouselView/2.3.0-pre1
and you can use it like so:
Namespace:
xmlns:cv="clr-namespace:Xamarin.Forms;assembly=Xamarin.Forms.CarouselView"
Then we can simply add the CarouselView at the top of our page:
<Grid RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height=".3*"/>
<RowDefinition Height=".7*"/>
</Grid.RowDefinitions>
<cv:CarouselView ItemsSource="{Binding Zoos}" x:Name="CarouselZoos">
<cv:CarouselView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Image Grid.RowSpan="2" Aspect="AspectFill" Source="{Binding ImageUrl}"/>
<StackLayout Grid.Row="1" BackgroundColor="#80000000" Padding="12">
<Label TextColor="White" Text="{Binding Name}" FontSize="16" HorizontalOptions="Center" VerticalOptions="CenterAndExpand"/>
</StackLayout>
</Grid>
</DataTemplate>
</cv:CarouselView.ItemTemplate>
</cv:CarouselView>
<!--List of Monkeys below-->
</Grid>
more info: https://blog.xamarin.com/flip-through-items-with-xamarin-forms-carouselview/
If you use Xamarin.Forms V2.2.0-pre1 and you need to display different views for each page, you can use a derived class like that:
public class CarouselViewMultiPage : CarouselView
{
List<View> _children = new List<View> { };
public List<View> Children {
get { return _children; }
set {
_children = value;
OnPropertyChanged();
}
}
public CarouselViewMultiPage ()
{
this.ItemTemplate = new CarouselTemplateSelector();
this.ItemsSource = Children;
this.SetBinding(CarouselView.ItemsSourceProperty, "Children");
BindingContext = this;
}
}
public class CarouselTemplateSelector : DataTemplateSelector
{
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
DataTemplate dt = new DataTemplate();
View civ = (View)item;
return new DataTemplate(() =>
{
return civ;
});
}
}
so you can call it passing Views:
public App()
{
// The root page of your application
MainPage = new ContentPage {
Content = new CarouselViewMultiPage
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
Children =
{
new Label() { Text="Page 1"},
new Label() { Text="Page 2"},
new Label() { Text="Page 3"},
}
}
};
}
CarouselView has been introduced in Xamarin forms v4.4. You can have a look at this. In additional to CarouselView, IndicatorView is also added to indicate the nth item in the carousel.