I want to make a comment entry that is only visible if the user is at the bottom of the article.
So the app has to recognize when the user has scrolled enough, then a method should make the entryfield visible.
I can't find something like this on the Internet, so maybe you guys can help me.
This one is without the entryfield and when the user scrolls down ...
... the entryfield becomes visible
If you are using a ScollView, there is a Scrolled event that fires whenever the view is scrolled and the ScrolledEventArgs contain ScrollX and ScrollY properties that allow you to know where the ScrollView currently is. If you compare ScrollY to the height of the ContentSize property of the ScrollView, e.g.:
XAML:
<StackLayout>
<ScrollView x:Name="scrollView" Scrolled="Handle_Scrolled">
<StackLayout>
<Label Text="{Binding Article}" HorizontalOptions="StartAndExpand" VerticalOptions="StartAndExpand" />
</StackLayout>
</ScrollView>
<Entry IsVisible="{Binding AtEnd}" Placeholder="End reached!" />
</StackLayout>
Code behind (MainPage is a ContentPage subclass):
string _article;
public string Article
{
get
{
return _article;
}
set
{
if (_article != value)
{
_article = value;
OnPropertyChanged("Article");
}
}
}
bool atEnd;
public bool AtEnd
{
get
{
return atEnd;
}
set
{
if (atEnd != value)
{
atEnd = value;
OnPropertyChanged("AtEnd");
}
}
}
public MainPage()
{
Article = "<put in enough text here to force scrolling>";
AtEnd = false;
InitializeComponent();
BindingContext = this;
}
void Handle_Scrolled(object sender, Xamarin.Forms.ScrolledEventArgs e)
{
if (e.ScrollY + scrollView.Height >= scrollView.ContentSize.Height)
AtEnd = true;
else
AtEnd = false;
}
That said, why not just put the entry below the article using the same scroll view? IOW just put the Entry element after the Label above in the same StackLayout and the Entry will just be there at the end always, but the user won't see it until they scroll down. Seems that that would be a simpler solution. Of course you may not be using a Label but the same applies, just put the Entry at the bottom of the layout that the ScrollView is scrolling.
Related
I wanted to add a scroll down prompt to ScrollView in my Xamarin app, for which I followed this article.
What it actually does is that it adds a scroll down indicator (Label) outside Scrollview, so if the text is more than the size of the page it shows this indication, written "Scroll down for more!", and when scrolling completely to the end, it hides this indicator.
This part is working, but if the text is less than the page, it still shows this scroll down indicator.
I want that if the text is less than the page, the visibility of the scroll down indicator should be false.
.xaml
<Grid>
<ScrollView x:Name="MyScrollView" Scrolled="MyScrollView_Scrolled">
<StackLayout>
<BoxView BackgroundColor="Red" HeightRequest="128"/>
<BoxView BackgroundColor="Orange" HeightRequest="128"/>
</StackLayout>
</ScrollView>
<Label x:Name="ScrollDownIndicator"
Text="Scroll down for more!"
BackgroundColor="Black"
TextColor="White"
FontSize="Large"
HorizontalTextAlignment="Center"
VerticalOptions="End"/>
</Grid>
.xaml.cs
private void MyScrollView_Scrolled(object sender, ScrolledEventArgs e)
{
double spaceAvailableForScrolling = MyScrollView.ContentSize.Height - MyScrollView.Height;
double buffer = 32;
ScrollDownPrompt.IsVisible = spaceAvailableForScrolling > e.ScrollY + buffer;
}
Juggling around with your code i came to a solution that might get you where you want.
Just looking for the fix? go and read Solution section. If you want to know the why, go ahead and read the Explanation section.
Solution
First of all, i realized that in the code you posted the Label in Xaml file is called ScrollDownIndicator, but in the event handler you are changing a variable called ScrollDownPrompt instead. On my tests i went ahead to equalize both names...
In your .xaml.cs file, add the following lines to your page constructor:
public MainPage()
{
InitializeComponent();
MyScrollView.PropertyChanged += (s, a) =>
{
if (a.PropertyName == ScrollView.ContentSizeProperty.PropertyName)
{
double buffer = 32;
double spaceAvailableForScrolling = MyScrollView.ContentSize.Height - MyScrollView.Height;
ScrollDownIndicator.IsVisible = spaceAvailableForScrolling > buffer;
}
};
}
private void MyScrollView_Scrolled(object sender, ScrolledEventArgs e)
{
double spaceAvailableForScrolling = MyScrollView.ContentSize.Height - MyScrollView.Height;
double buffer = 32;
ScrollDownPrompt.IsVisible = spaceAvailableForScrolling > e.ScrollY + buffer;
}
Explanation
In your code you only change the visibility of the Indicator from the event handler: MyScrollView_Scrolled. If no scrolling is performed, the event handler is not called and no visibility of the indicator is checked: it is simply always visible.
To correct this behavior you have to check the visibility when the ContentSize property of ScrollView changes.
Hope this helps some people :D
-> xamarin forms resize listview (inside stacklayout) after each keyboard entry - from code behind
(would like this cross platform if it is possible?)
Using SearchBar to allow user to search for products of wines... when text is changed the displayed results are updated correctly but I want to change the size of the ListView to only show results removing any empty white space.
So for example in attached picture entry 'Wine ' returns 12 results, which shows all....but 'Wine 1' only 4 results. So I would like the ListView to end after 'wine 12'(from the results) instead the opacity covers the rest of the screen.
Have tried some examples such as:
ListView inside StackLayout: How to auto resize the ListView?
but still cant get it going does anyone see what I am doing wrong thank you
<NavigationPage.TitleView>
<StackLayout HorizontalOptions="StartAndExpand" Orientation="Horizontal">
<SearchBar x:Name="SearchBar" TextChanged="SearchBar_TextChanged" HorizontalOptions="FillAndExpand" Placeholder="Search..." PlaceholderColor="Gray" TextColor="White" VerticalOptions="StartAndExpand"/>
</StackLayout>
</NavigationPage.TitleView>
private void SearchBar_TextChanged(object sender1, TextChangedEventArgs e1)
{
StackSearchResults.IsVisible = true;
int numberOfProducts = 0;
SearchListView.ItemsSource = GetProducts(out numberOfProducts, e1.NewTextValue);
SearchListView.RowHeight = 50;
SearchListView.PropertyChanged += (object sender, System.ComponentModel.PropertyChangedEventArgs e) =>
{
if (e.PropertyName == "ItemsSource")
{
try
{
if (SearchListView.ItemsSource != null)
{
SearchListView.HeightRequest = numberOfProducts * 50;
}
}
catch (Exception ex)
{
}
}
};
}
you only need to assign the PropertyChanged handler once, not every time TextChanged fires. That is probably not the root issue, but it's not helping. You should also be sure you're assigning the HeightRequest on the UI thread
How to Lable Hide and show if admin is login then one label is displayed otherwise label is hidden {How Solve it} ?
xaml Code
<StackLayout IsVisible="{Binding IsAdminTrue}">
<Label Text="is_professional"></Label>
</StackLayout>
ViewModel Code
public void IsProfessional()
{
if (CurrentUser.IsAdmin!= true)
{
IsAdminTrue= false;
}
else
{
IsAdminTrue= true;
}
}
public void IsProfessional()
{
if (CurrentUser.IsAdmin!= true)
{
lblNo.Visibility= Visibility.Visible;
}
else
{
lblNo.Visibility = Visibility.Hidden;
}
}
Here lblNo is an label.
You should set the Visibility property on the Label, not the StackLayout. You could either change IsAdminTrue to IsAdminVisible (of type Visibility), or you could use the BooleanToVisibility converter. Second option is usually the preferred method.
Of course, none of this will matter if IsAdminTrue doesn't raise PropertyChanged.
I have bind on my ListView, an ObersvableCollection.
And i want to alternate my row color of my ListView.
I found lot of code, but didn't work for me... If you can share an example/sample !
Like this :
But i don't know how i can do that ?
I work with Visual Studio 2015 / Xamarin forms.
My project must be work with Android and IOS.
Thank for your help!
You can use a custom ListView for that. This works, if your Cell inherits from ViewCell.
public class AlternatingListView : ListView
{
public AlternatingListView(ListViewCachingStrategy cachingStrategy) : base(cachingStrategy)
{
}
protected override void SetupContent(Cell content, int index)
{
base.SetupContent(content, index);
var viewCell = content as ViewCell;
viewCell.View.BackgroundColor = index % 2 == 0 ? Color.Blue : Color.Red;
}
}
There's no built in way to do this with XF. The simplest approach would be to include an Index property in your Item model (you would have to set it manually as you add it to your List/Collection) that determines the color. You could then bind the RowColor property to your ItemTemplate.
public class MyItem {
public int Index { get; set; }
public string Name { get; set; }
public Color RowColor {
get {
if (Index % 2) == 0))
return Color.Red;
else
return Color.Blue;
}
}
}
You could also use a ValueConverter to determine the Color based on the Index row - this would free your model from having to determine it's own color, which would be a cleaner implementation.
Another option would be adding it to the objects contained within the listview itself before passing the listview into the binding context.
So for example, when requesting lists from an API and deserializing them, you can then proceed to iterate and assign a background color property to each object within the list:
var response = client.GetAsync(EndPointHelper.GetEndPoint("MaintenanceForEquipment") + "/" + equipmentid).Result;
var content = await response.Content.ReadAsStringAsync();
var contentmaintenances = JsonConvert.DeserializeObject<List<Maintenance>>(content);
var count = 1;
foreach (var maint in contentmaintenances)
{
maint.BackgroundColor = count % 2 == 0 ? "#A1DBE4" : "#155DB0";
maint.TextColor = count % 2 == 0 ? "#529CFF" : "#e9ecf0";
count++;
}
From there, you can access it in the ItemTemplate within your list view after assigning the records accessed to the binding context:
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="{Binding BackgroundColor}"
Orientation="Vertical">
<StackLayout Orientation="Horizontal">
<Label Text="{Binding EquipmentName}"
TextColor="{Binding TextColor}" FontSize="Medium"/>
<Label Text="{Binding StartDateString}" TextColor="{Binding TextColor}"></Label>
<Label Text="{Binding MaintenanceTypeName}"
HorizontalOptions="EndAndExpand"
TextColor="{Binding TextColor}" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
If you want to use fewer iterations within your Xamarin code, you can implicitly generate the background color via whatever API you're working with assuming you have access to that as well so it only needs to be assigned one time and accessed again on the client side after calling the API.
Hope this helps anyone looking through this old question for another possible solution.
You can use a custom view cell. I've written a custom view cell in my project and used XFGloss(XFGloss is an add-on for Xamarin.Forms projects that adds new properties to the standard XF page and control classes) to make the listView's rows colorful. Your listView will not lose the haptic feedback with XFGloss. It works with grouped listViews too. The custom viewCell which I used is :
public class MyViewCell : ViewCell
{
private Color BackgroundColor
{
get => CellGloss.GetBackgroundColor(this);
set => CellGloss.SetBackgroundColor(this, value);
}
public Color EvenColor { get; set; }
public Color UnevenColor { get; set; }
protected override void OnAppearing()
{
base.OnAppearing();
if (!(Parent is ListView listView))
throw new Exception(
$"The Binding Context is not {typeof(ListView)}. This component works only with {typeof(ListView)}.");
int index;
if (listView.IsGroupingEnabled)
{
index = listView.TemplatedItems.GetGroupAndIndexOfItem(BindingContext).Item2;
}
else
{
index = listView.TemplatedItems.IndexOf(this);
}
if (index != -1)
BackgroundColor = index % 2 == 0 ? EvenColor : UnevenColor;
}
}
and its usage in the xaml file is simple as below line :
<components:MyViewCell EvenColor="White" UnevenColor="#eeeeee">
I am trying to dynamically show/hide button inside Xamarin Forms ContentPage.
I have two buttons in my XAML code:
<StackLayout Orientation="Vertical">
<Button x:Name="start_btn" Clicked="startPanic">
<Button.Text>START</Button.Text>
</Button>
<Button x:Name="stop_btn" IsVisible="false">
<Button.Text>STOP</Button.Text>
</Button>
</StackLayout>
Corresponding C# code:
public partial class PanicPage : ContentPage
{
private Button startBtn;
private Button stopBtn;
public PanicPage ()
{
InitializeComponent ();
startBtn = this.FindByName<Button> ("start_btn");
stopBtn = this.FindByName<Button> ("stop_btn");
}
private void startPanic(object sender, EventArgs args){
Device.BeginInvokeOnMainThread (() => {
startBtn.IsVisible = false;
stopBtn.IsVisible = true; // DOESN'T WORK, button still will be hidden
});
}
}
When I set isVisible property in XAML, it doesn't react for any property change in event method (startPanic). How can I fix it?
Change your code in xmal file and write properties for start and stop button
<Button x:Name="start_btn" Clicked="startPanic" IsVisible="{Binding IsStartVisible}">
<Button.Text>START</Button.Text>
</Button>
<Button x:Name="stop_btn" IsVisible="{Binding IsStopVisible}">
<Button.Text>STOP</Button.Text>
</Button>
In ViewModel write following property and similar for start button and set IsStopVisible =true/false based on your logic
private bool _isStopVisible;
public bool IsStopVisible{
get {
return _isStopVisible;
}
set {
_isStopVisible= value;
RaisePropertyChanged ("IsStopVisible");
}
}
Maybe I'm late but I was searching this too without success. This may be useful for someone.
objectView.SetValue(IsVisibleProperty, false); // the view is GONE, not invisible
objectView.SetValue(IsVisibleProperty, true);
It should work just fine. I copied your code and cleaned it up a bit, it shows the STOP button, then I
A few remarks:
use the short property where possible <Button Text="X"/>, it's
easier to read
when you add a XAML page the IDE adds a .xaml.cs file next to it and generates another .g.cs that you don't see. The .g.cs file
contains generated code that finds all the x:Name'd elements and
defines placeholders for them, no need to find them by name yourself
all UI-initiated events are executed on the UI thread, no need to do that explicitly
Here's the XAML, same as yours just tighter and added Margin so the button is visible
<StackLayout Orientation="Vertical" Margin="20">
<Button x:Name="start_btn" Clicked="startPanic" Text="START" />
<Button x:Name="stop_btn" Text="STOP" IsVisible="false" />
</StackLayout>
And the code behind:
public partial class TestPage : ContentPage
{
public TestPage ()
{
InitializeComponent ();
}
private void startPanic(object sender, EventArgs args){
Device.BeginInvokeOnMainThread (() => {
start_btn.IsVisible = false;
stop_btn.IsVisible = true;
});
}
}
Use the Visibility property of view.
for example if u want to make your button invisible you can do
if(condition)
{
button.Visibility=ViewStates.Invisible;
}
else
{
button.Visibility=ViewStates.Visible;
}