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
Related
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
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.
Creating a Registration page, I need to get the following data from user.
First Name
Last Name
Username
Email
Password
Date of Birth
Gender
User Role
For the last two parameters, I am unable to find how to use radio buttons in Xamarin.Forms. Following is my code for the Registration Page.
<StackLayout BackgroundColor="#30af91" Padding="60">
<Entry Text="{Binding FirstName}" Placeholder="First Name"/>
<Entry Text="{Binding LastName}" Placeholder="Last Name"/>
<Entry Text="{Binding UserName}" Placeholder="Last Name"/>
<Entry Text="{Binding Email}" Placeholder="Email" />
<Entry Text="{Binding Password}" Placeholder="Password" IsPassword="True"/>
<Entry Text="{Binding ConfirmPassword}" Placeholder="Confirm Password" IsPassword="True"/>
<DatePicker MinimumDate="1/1/1948" MaximumDate="12/31/2007"/>
<!--Radio buttons for Gender
1. Male 2.Female-->
<!--Radio Buttons for UserRole
1. Admin 2.Participant-->
<Button Command="{Binding RegisterCommand}" Text="Register"/>
<Label Text="{Binding Message}" />
</StackLayout>
Xamarin forms does not provide Radio Button.
You can either use
1)Switch
2)Picker
or any other component to fulfill your requirement
UPDATE
The xamarin forms update version 4.6 has introduced the Radio button control, Here is the official documentation
I think there is a simpler solution that is fairly easy and requires no libraries. Really a a radio group is just a fancy ListView. You would just need to create a viewModel for each radio button that has a IsSelected flag and switch between 2 images. I had a need to allow a user to select how long a token persisted:
XAML
<ListView
HasUnevenRows="True"
HorizontalOptions="FillAndExpand"
ItemsSource="{Binding Durations}"
ItemSelected="ListView_ItemSelected"
SelectedItem="{Binding SelectedDuration}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout
Orientation="Horizontal">
<Image
HeightRequest="18"
IsVisible="{Binding IsSelected}"
Source="radioButtonChecked.png"
WidthRequest="18"/>
<Image
HeightRequest="18"
IsVisible="{Binding IsUnselected}"
Source="radioButtonUnchecked.png"
WidthRequest="18"/>
<Label
Margin="8,0,0,0"
Text="{Binding Caption}"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
We create a listview in our content page and listen for the ItemSelected event. Each list item is a horizontal stack panel where we flip between two images depending on the selected state
Code Behind
public partial class LoginPage : ContentPage
{
LoginPageViewModel LoginPageViewModel { get; }
public LoginTwoFactorFrequencyPage ()
{
BindingContext = LoginPageViewModel = new LoginPageViewModel();
InitializeComponent ();
}
private void ListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
LoginPageViewModel.UpdateSelected(e.SelectedItem as PersistenceDuration);
}
}
The page's code behind instantiates a view model and calls an UpdateSelected method with the newly selected item on the page's view model*
RadioButton ViewModel
The view model for each radio button:
public class PersistenceDuration : ViewModelBase
{
bool isSelected;
public string Caption { get; set; }
public TwoFactorTokenPersistenceDuration Duration { get; set; }
public bool IsSelected
{
get => isSelected;
set
{
isSelected = value;
OnPropertyChanged();
OnPropertyChanged("IsUnselected");
}
}
public bool IsUnselected => !IsSelected;
public PersistenceDuration(string caption, TwoFactorTokenPersistenceDuration duration)
{
Caption = caption;
Duration = duration;
IsSelected = false;
}
}
The radio button view model holds selection info and the caption. We make sure to fire OnPropertyChanged whenever the selected state changes
Page ViewModel
public class LoginPageViewModel : ViewModelBase
{
PersistenceDuration duration;
PersistenceDuration selectedDuration;
public ObservableCollection<PersistenceDuration> Durations { get; }
public PersistenceDuration SelectedDuration
{
get => selectedDuration;
set
{
if (value != null)
{
duration = value;
UpdateSelected(duration);
}
OnPropertyChanged();
}
}
public LoginTwoFactorFrequencyViewModel()
{
Durations = new ObservableCollection<PersistenceDuration>(
new List<PersistenceDuration>()
{
new PersistenceDuration(AppResources.Save_code__forever, TwoFactorTokenPersistenceDuration.Forever),
new PersistenceDuration(AppResources.ChatRequireEvery30Days, TwoFactorTokenPersistenceDuration.ThirtyDays),
new PersistenceDuration(AppResources.ChatRequireEveryLogin, TwoFactorTokenPersistenceDuration.None),
});
}
public void UpdateSelected(PersistenceDuration persistenceDuration)
{
foreach (var item in Durations)
item.IsSelected = persistenceDuration == item;
}
}
In the page view model we create a list of radio button view models that the XAML binds to. When we UpdateSelected() all the IsSelected states are updated which trigger binding updates which flip the image.
You will still need to do something about the highlight when someone selects an item, but that is easy enough to find on the internet :)
You can use XLabs plugin from manage NuGets package. After installing you can use like this:
In Xaml:
controls:BindableRadioGroup x:Name="Radiobtn"
In C#:
string[] gender = {"MAlE","FEMALE"}
Radiobtn.Add(gender)
Refer Link
https://github.com/XLabs/Xamarin-Forms-Labs/tree/master/samples/XLabs.Samples/XLabs.Samples/Pages/Controls
You can get the radio button effect without a package. Use Labels with text unicode circle \u26AA or \u25CB. Attach a tab gesture recognizer to each label.
When tapped, change the text of the selected button to unicode circle bullet \u29BF and change the text of the other button(s) back to unicode circle \u26AA.
Test on your preferred platforms as each platform may display somewhat differently. You may need to adjust the font size as you change the text.
If you want real radiobuttons you can xlabs their package (https://github.com/XLabs/Xamarin-Forms-Labs/tree/master/src/Forms/XLabs.Forms/Controls/RadioButton)
Personally I'd just use a picker, Xlabs package hasn't been updated in a while so their might be some bugs in the radiobutton
You can use image as a radio button. When tou you click on it, it can change. It is not a good way to do it though.
This is xaml code:
<Image Scale="0.7" HorizontalOptions="Start" x:Name="radioButton" Source="unRadioBtn.png">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="radioButton_Clicked"></TapGestureRecognizer>
</Image.GestureRecognizers>
</Image>
And this is .cs:
private void radioButton_Clicked(object sender, EventArgs e)
{
radioButton.Source = "radioBtn.png";
}
Xamarin.Forms 4.6 introduced a new RadioButton control. You can find the documentation here: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/radiobutton
You can use the switch component. Also you can see the implementation for a checkbox component from the XLabs project which is now discontinued, get the code and modify it as you need.
Hint: You're gonna need the custom renderers per platform for it to work .
You need to use Picker
https://developer.xamarin.com/api/type/Xamarin.Forms.Picker/
Actually it is the best alternative to RadionButton On Xamarin.forms
XLabs RadioButton and BindableRadioGroup work well: XLabs RadioButton for Xamarin Forms
Here's a simple Yes/No radio using the BindableRadioGroup:
var answers = new List<string>();
answers.Add("Yes");
answers.Add("No");
var RadioGroup = new XLabs.Forms.Controls.BindableRadioGroup()
{
ItemsSource = answers,
Orientation = StackOrientation.Horizontal
};
Xamarin Forms now provides a Radio Button control.
See docs here:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/radiobutton
As of XF 4.8 this is still experimental and I've not yet used this feature so can't comment on its stability.
I'm using pivot control to display a large number of images (about 300). I thought of just using 3 pivot item, and when user swipes, change either pivot item or update item source. But I don't know how to do this efficiently ?
Or is there a way of using gesture and stimulating swipe effect as the pivot does ? Something like transition ?
You can use normal Image Control with gesture Manipulation events to swipe left to right and right to left for previous/next photos.
Please find the code below.
XAML Code
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Margin="0">
<Image Margin="0" x:Name="ImagePanel" Source="{Binding SelectedPhoto.PhotoURL}" Stretch="Uniform" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
C# code
public SlideShow()
{
// Tag ManipulationCompleted event for the current page in the constructor.
ManipulationCompleted += new EventHandler<ManipulationCompletedEventArgs>(SlideShow_ManipulationCompleted);
}
// ManipulationCompleted event. Update the Previous/next photo based on the swipe direction.
void SlideShow_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
var manipEndPoint = e.TotalManipulation.Translation;
const int threshold = 100;
if ((manipEndPoint.X > _manipStartPoint.X) && ((manipEndPoint.X - _manipStartPoint.X) > threshold))
{
LoadPreviousPhoto();
}
else if ((manipEndPoint.X < _manipStartPoint.X) && ((_manipStartPoint.X - manipEndPoint.X) > threshold))
{
LoadNextPhoto();
}
}
Let me know if you need any more help.
Thanks,
Kamal.