After zooming the image in CarouselView and swiping to next image, the previous image is not display in it's original form it is in zoom type image - xamarin

After Zooming the image in CarouselView and swiping the image to other image and coming back to that image which i had zoomed the image is already zoomed, as i want the image should come to its original form when i swipe to other image.
Here is my below XMAl code:-
<cards:CarouselView Grid.Row="1" PositionChanged="ImageCollection_PositionChanged" CurrentItemChanged="ImageCollection_CurrentItemChanged_1" IndicatorView="{x:Reference imageIndicator}" x:Name="ImageCollection">
<cards:CarouselView.ItemTemplate>
<DataTemplate>
<ContentView>
<Grid Padding="0" Margin="0">
<pinch:PinchZoom>
<pinch:PinchZoom.Content>
<Image Source="{Binding image}" x:Name="ImageData" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Aspect="AspectFill">
</Image>
</pinch:PinchZoom.Content>
</pinch:PinchZoom>
</Grid>
</ContentView>
</DataTemplate>
</cards:CarouselView.ItemTemplate>
</cards:CarouselView>

You can refer to the following code. When you click the button, the image will display original size. You can add the code of Button_Clicked to PositionChanged or CurrentItemChanged:
MainPage.xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"             
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"             
x:Class="Forms_CarouseIView.MainPage"             
xmlns:local="clr-namespace:Forms_CarouseIView;assembly=Forms_CarouseIView">    
<ContentPage.Content>        
<StackLayout Padding="20"
x:Name="stacklayout">            
<local:PinchToZoomContainer x:Name="PinchToZoomContainer">                
<local:PinchToZoomContainer.Content >                    
<Image Source="ddd.png"/>
</local:PinchToZoomContainer.Content>            
</local:PinchToZoomContainer>            
<Button Text="reset" Clicked="Button_Clicked"/>        
</StackLayout>            
</ContentPage.Content>
</ContentPage>
MainPage.xaml.cs:
namespace Forms_CarouseIView
{    
public partial class MainPage : ContentPage    
{        
public static double scale1;        
public static double tx;        
public static double ty;  
      
public MainPage()        
{            
InitializeComponent();        
}  
      
private void Button_Clicked(object sender, EventArgs e)        
{            
PinchToZoomContainer.Content.Scale=scale1;            
PinchToZoomContainer.TranslationX=tx;            
PinchToZoomContainer.TranslationY=ty;                   
}    
}
}
PinchToZoomContainer.cs:
namespace Forms_CarouseIView
{    
public class PinchToZoomContainer : ContentView    
{           
...      
void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)        
{            
if (e.Status == GestureStatus.Started)            
{                
...
               
MainPage.scale1 = Content.Scale;                                
  }            
if (e.Status == GestureStatus.Running)            
{                
...            
}            
if (e.Status == GestureStatus.Completed)            
{                
...
                 
MainPage.tx = -xOffset;                
MainPage.ty = -yOffset;            
}        
}    
}
}
For more code about PinchToZoomContainer.cs, you can refer to Creating a PinchToZoom container by official.

Related

Xamarin listview button click get command argument value

I have this listview
<ListView x:Name="LocationsListView" ItemsSource="{Binding ListOfFuel}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<StackLayout>
<Button CommandParameter="{Binding Id}" Clicked="Button_Clicked"></Button>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
With the code behind event I want to get the CommandParameter which is part of the ItemsSource list, the Id value.
I'm doing this:
private void Button_Clicked(object sender, EventArgs e)
{
Button btn = (Button)sender;
int Idvalue = btn.Id;
}
With this approach the app is complaining that the button Id is guid value but in the list I have Id as integer, so I'm assuming the Id is some kind of identification for the button itself not the actual Id value from the items source.
What are my options to find out on button click the listview id or some other property in that list?
You can only get the CommandParameter in Command .
In xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="xxx.MainPage"
x:Name="contentPage">//set the name of contentPage here
<StackLayout>
<Button CommandParameter="{Binding Id}" Command="{Binding Source={x:Reference contentPage}, Path=BindingContext.ClickCommand}"></Button>
</StackLayout>
And in your ViewModel:
public ICommand ClickCommand { get; set; }
//...
public MyViewModel()
{
//...
ClickCommand = new Command((arg)=> {
Console.WriteLine(arg);
});
}
arg here is the CommandParameter that you binding the value of property Id
I can give you two solutions to this.
1. Instead of using a Button inside Nested StackLayout you can use ItemSelected Event of Listview. In that method you can get the entire Item using e.SelectedItem and the cast it to your class type
ListView.ItemSelected += (object sender, SelectedItemChangedEventArgs e) =>
{
var item = (YourClass) e.SelectedItem;
// now you can any property of YourClass.
};
You can find the highest Parent and then get it's BindingContext.
private void Button_Clicked(object sender, EventArgs e)
{
StackLayout stc = ((sender as Button).Parent as StackLayout).Parent as StackLayout;
// Then get the BindingContext
}

page not scrolled when clicked input and display keyboard in webview xamarin forms

I try to develop android apps using Xamarin Forms.
There is an input in a webview.When clicked the input , keyboard is displayed.But i can not see what i write.Input is not scrolled up.
XAML and WebViewRenderer contents as below.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:deneme"
">
<ContentPage.Content>
<ScrollView>
<Grid>
<Grid.ColumnDefinitions>.ColumnDefinitions>
<Grid.RowDefinitions>.RowDefinitions>
<local:HybridWebView x:Name="webView" Grid.Row="0" Grid.ColumnSpan="2">
</local:HybridWebView>
<Button Text="Button1" Grid.Column="0" Grid.Row="1"/>
<Button Text="Button2"/>
<Label Text="Hidden"/>
</Grid>
</ScrollView>
</ContentPage.Content>
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, Android.Webkit.WebView>
{
Context _context;
public HybridWebViewRenderer(Context context) : base(context)
{
_context = context;
}
protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
var webView = new Android.Webkit.WebView(_context);
webView.ScrollBarFadeDuration = 0;
webView.Settings.JavaScriptEnabled = true;
webView.SetWebViewClient(new JavascriptWebViewClient($"javascript: {JavascriptFunction}"));
SetNativeControl(webView);
}
}
}
In order to set html input position prior keyboard,what should i do ?
You can use Soft Keyboard Input Mode on Android described in the document.
In xaml:
<Application ...
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:Application.WindowSoftInputModeAdjust="Resize">
...
</Application>
Or in code behind:
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
...
App.Current.On<Android>().UseWindowSoftInputModeAdjust(WindowSoftInputModeAdjust.Resize);
Refer: keyboard-hides-textarea-inside-a-hybrd-webview-in-xamarin-forms
Take a look here in the Android docs and especially the android:windowSoftInputMode (docs) attribute of activity.
Just add this line to your code
Window.SetSoftInputMode(SoftInput.AdjustPan);

How to implement animation when Image source changed?

I am working on xamarin.forms and want to start an animation when the image source are changed.
<ListView >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Image Source="{Binding FavoriteImage}" x:Name="favoriteImage">
<Image.GestureRecognizers>
TapGestureRecognizer Command="{Binding Source={x:Reference CurrentPage},Path=BindingContext.ClickLikedCommand}" CommandParameter="{Binding .}" NumberOfTapsRequired="1"/>
</Image.GestureRecognizers>
</Image>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The image source is bind to an variable in the ViewModel and will be changed if user click the image and get a successful response from server. Then the new Image will be shown with some custom animation, so where can I trigger this animation since the image source changed?
I have read the "Behavior" and "Trigger" tutorial online, It seems it could trigger an animation by an event, but Image class has not such an "SourceChanged" event.
You can use the OnPropertyChanged method:
public class ExImage : Image
{
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == nameof(Source))
Device.BeginInvokeOnMainThread(async () =>
{
await this.ScaleTo(1.2);
await this.ScaleTo(1);
});
}
}

How can I make the Tapped event of a ViewCell send a param to a generic function and then open up a picker for that ViewCell element?

Update: Just a reminder, there's a 500 point bonus on this if someone can just show me how to implement this functionality without using Gestures>
I am using a ViewCell and a gesture recognizer to open up a picker with the following code. The ViewCell has a label on the left and a label area on the right that is populated initially when the app starts and later with the picker when the ViewCell is clicked.
XAML
<ViewCell x:Name="ati" Tapped="OpenPickerCommand">
<Grid VerticalOptions="CenterAndExpand" Padding="20, 0">
<Grid.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding OpenPickerCommand}"
CommandParameter="{x:Reference atiPicker}" NumberOfTapsRequired="1" />
</Grid.GestureRecognizers>
<local:LabelBodyRendererClass Text="Answer Time Interval" HorizontalOptions="StartAndExpand" />
<Picker x:Name="atiPicker" IsVisible="false" HorizontalOptions="End" SelectedIndexChanged="atiPickerSelectedIndexChanged" ItemsSource="{Binding Times}"></Picker>
<local:LabelBodyRendererClass x:Name="atiLabel" HorizontalOptions="End"/>
</Grid>
</ViewCell>
<ViewCell x:Name="pti" Tapped="OpenPickerCommand">
<Grid VerticalOptions="CenterAndExpand" Padding="20, 0">
<Grid.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding OpenPickerCommand}"
CommandParameter="{x:Reference ptiPicker}" NumberOfTapsRequired="1" />
</Grid.GestureRecognizers>
<local:LabelBodyRendererClass Text="Phrase Time Interval" HorizontalOptions="StartAndExpand" />
<Picker x:Name="ptiPicker" IsVisible="false" HorizontalOptions="End" SelectedIndexChanged="ptiPickerSelectedIndexChanged" ItemsSource="{Binding Times}"></Picker>
<local:LabelBodyRendererClass x:Name="ptiLabel" HorizontalOptions="End"/>
</Grid>
</ViewCell>
C# This works for different pickers (ati, bti, pti etc) with CommandParameter
public SettingsPage()
{
InitializeComponent();
BindingContext = new CommandViewModel();
}
void atiPickerSelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
int selectedIndex = picker.SelectedIndex;
if (selectedIndex != -1)
{
App.DB.UpdateIntSetting(Settings.Ati, selectedIndex);
atiLabel.Text = AS.ati.Text();
}
}
void ptiPickerSelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
int selectedIndex = picker.SelectedIndex;
if (selectedIndex != -1)
{
App.DB.UpdateIntSetting(Settings.Pti, selectedIndex);
ptiLabel.Text = AS.pti.Text();
}
}
public class CommandViewModel: ObservableProperty
{
public ICommand openPickerCommand;
public CommandViewModel()
{
openPickerCommand = new Command<Picker>(PickerFocus);
//openPickerCommand = new Command(tapped);
}
public ICommand OpenPickerCommand
{
get { return openPickerCommand; }
}
void PickerFocus(Picker param)
{
param.Focus();
}
}
I would like to remove the use of TapGestureRecognizers but I still want to retain the functionality and layout.
It's been suggested to me that it would be better if I used the Tapped event of the ViewCell like this:
Tapped="OnTapped"
Can someone explain in some detail how I could wire this up in C#. Would I be best to code something into the CommandViewModel as well as in the C# backing code. Also can the view model have one method that takes an argument so it could be used to open up different pickers?
An example of how I could do this would be very much appreciated. Note that I don't particularly need to use the CommandViewModel if there is a way that I could do this by coding just in the .cs backing code.
(Sorry for the poor english)
Despite not being best practice, I guess you can do something like this, dismissing the viewmodel:
XAML:
<ViewCell x:Name="ati" Tapped="OpenPickerCommand">
<Grid VerticalOptions="CenterAndExpand" Padding="20, 0">
<local:LabelBodyRendererClass Text="Answer Time Interval" HorizontalOptions="StartAndExpand" />
<Picker x:Name="atiPicker"
IsVisible="false"
HorizontalOptions="End"
SelectedIndexChanged="atiPickerSelectedIndexChanged"
ItemsSource="{Binding Times}">
</Picker>
<local:LabelBodyRendererClass x:Name="atiLabel" HorizontalOptions="End"/>
</Grid>
</ViewCell>
<ViewCell x:Name="pti" Tapped="OpenPickerCommand">
<Grid VerticalOptions="CenterAndExpand" Padding="20, 0">
<local:LabelBodyRendererClass Text="Phrase Time Interval" HorizontalOptions="StartAndExpand" />
<Picker x:Name="ptiPicker" IsVisible="false" HorizontalOptions="End" SelectedIndexChanged="ptiPickerSelectedIndexChanged" ItemsSource="{Binding Times}"></Picker>
<local:LabelBodyRendererClass x:Name="ptiLabel" HorizontalOptions="End"/>
</Grid>
</ViewCell>
C#:
private void OpenPickerCommand(object sender, System.EventArgs e)
{
if (sender != null)
{
Picker pkr = sender == ati ? atiPicker : ptiPicker;
pkr.Focus();
}
}
Answering your question "Can the view model have one method that takes an argument?", it is exactly what you're already doing using the 'OpenPickerCommand' method. The problem is that using the ViewCell's public event 'Tapped', you can't set parameters to the delegate handler.
Let me know if it works for you or if you do need some more information.
I hope it helps.
You can solve this with attached properties. Simply define a "behavior" class for ViewCell that adds the Command/Parameter properties.
public static class TappedCommandViewCell
{
private const string TappedCommand = "TappedCommand";
private const string TappedCommandParameter = "TappedCommandParameter";
public static readonly BindableProperty TappedCommandProperty =
BindableProperty.CreateAttached(
TappedCommand,
typeof(ICommand),
typeof(TappedCommandViewCell),
default(ICommand),
BindingMode.OneWay,
null,
PropertyChanged);
public static readonly BindableProperty TappedCommandParameterProperty =
BindableProperty.CreateAttached(
TappedCommandParameter,
typeof(object),
typeof(TappedCommandViewCell),
default(object),
BindingMode.OneWay,
null);
private static void PropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is ViewCell cell)
{
cell.Tapped -= ViewCellOnTapped;
cell.Tapped += ViewCellOnTapped;
}
}
private static void ViewCellOnTapped(object sender, EventArgs e)
{
if (sender is ViewCell cell && cell.IsEnabled)
{
var command = GetTappedCommand(cell);
var parameter = GetTappedCommandParameter(cell);
if (command != null && command.CanExecute(parameter))
{
command.Execute(parameter);
}
}
}
public static ICommand GetTappedCommand(BindableObject bindableObject) =>
(ICommand)bindableObject.GetValue(TappedCommandProperty);
public static void SetTappedCommand(BindableObject bindableObject, object value) =>
bindableObject.SetValue(TappedCommandProperty, value);
public static object GetTappedCommandParameter(BindableObject bindableObject) =>
bindableObject.GetValue(TappedCommandParameterProperty);
public static void SetTappedCommandParameter(BindableObject bindableObject, object value) =>
bindableObject.SetValue(TappedCommandParameterProperty, value);
}
After that reference your behavior namespace in XAML and specify the property values using fully qualified names:
<ViewCell StyleId="disclosure-indicator"
behaviors:TappedCommandViewCell.TappedCommand="{Binding BrowseCommand}"
behaviors:TappedCommandViewCell.TappedCommandParameter="https://www.google.com">
<StackLayout Orientation="Horizontal">
<Label Text="Recipient"
VerticalOptions="Center"
Margin="20,0"/>
<Label Text="{Binding LedgerRecord.Recipient}"
HorizontalOptions="EndAndExpand"
VerticalOptions="Center"
Margin="0,0,20,0"/>
</Label>
</StackLayout>
</ViewCell>
The above will allow you to use MVVM and no Tap Gesture Recognizers.
The first problem is that you're mixing the code-behind and MVVM
approaches in the same code. It is confusing and certainly not the
right way to code what you want to achieve. So, all commanding must
be in the ViewModel attached to the View, no code-behind apart some
code only used for UI effects.
There is no need to define a gesture recognizer for all visual items since you just want to detect the tap on all the surface of the viewcell. To achieve this you must define all children of the ViewCell with InputTransparent=true. So the tap will not be detected and will be trapped by the parent ViewCell (you
must indicate the InpuTransparent because there is no tap event
bubbling in X.Forms).
Showing and Hidding the picker is a View problem not a ViewModel one. So here you can use some code-behind to create an event handler for the ViewCell Tapped event. This handler will just set visible=true on the picker.
The picker selected event must be connected to a corresponding Command in the ViewModel. So each time the picker is displayed and a value is selected your viewmodel will be aware of the action. This is the only command you need in your viewmodel. Depending of XForms version the picker has no bindable command, so you can use one of the numerous "bindablepicker" implementation you can find on the web or you can also use a XAML EventToCommand Behavior.
So there is two different problems : showing/hidding the picker which can be achieved directly in XAML or with the help of a bit of code-behind; and the picker item selection that must be managed using a Command in the viewmodel.
Hoping this will help you

How to go to another screen from one screen in Xamarin cross-platform?

I am new in Xamarin and I want to go to another screen from one screen. I have a button in first screen and I want to open another screen after clicking on that button.
How can I do this?
Here is the code I have tried so far:
XAML Layout (FirstXAML.xaml)
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="AllControlsDemo.FirstXaml">
<StackLayout>
<Slider x:Name="sldr"
VerticalOptions="CenterAndExpand"
ValueChanged="OnSliderValueChanged" />
<Label x:Name="lblValue"
Text="A simple Label"
Font="Large"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button x:Name="btnClickme"
Text="Click Me!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
Clicked="OnbtnClickme" />
<Button x:Name="btnSecondXaml"
Text="Second Xaml!"
HorizontalOptions="Center"
VerticalOptions="StartAndExpand"
Clicked="OnbtnSecondXaml" />
</StackLayout>
</ContentPage>
Code of (FirstXAML.xaml.cs)
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace AllControlsDemo
{
public partial class FirstXaml : ContentPage
{
private Label valueLabel;
float count = 0.050f;
private Slider slider;
public FirstXaml ()
{
InitializeComponent ();
valueLabel = this.FindByName<Label>("lblValue");
slider = this.FindByName<Slider> ("sldr");
}
void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
valueLabel.Text = ((Slider)sender).Value.ToString("F3");
count = float.Parse(valueLabel.Text);
}
void OnbtnClickme(object sender, EventArgs args)
{
count += 0.050f;
slider.Value = count;
}
void OnbtnSecondXaml(object sender, EventArgs args)
{
// Write code here to move on second Xaml
}
}
}
I am also new on Xamarin. I copied your code and solved your problem.
Try this:
void OnbtnSecondXaml(object sender, EventArgs args)
{
// Write code here to move on second Xaml
Navigation.PushModalAsync(new SecondXaml());
}
This is what NavigationPage is for. You need to wrap FirstXAML inside of a NavigationPage, then you can use the Navigation property to navigate to other pages.
Navigation.PushAsync(page2);
Also, you do not need to use FindByName to assign local variables for controls in your xaml. Any control with a x:name property will automatically be assigned a local variable.

Resources