How to change opacity on MaterialCard clicked? - xaml

In my HomePage.xaml I have material:MaterialCard.
<material:MaterialCard Grid.Column="0"
BackgroundColor="{StaticResource CustomizedRedColor}"
WidthRequest="70"
HeightRequest="70"
VerticalOptions="Center"
CornerRadius="4"
Elevation="1"
Padding="5"
x:Name="CreateMQRCard"
Opacity="{Binding Opacity}"
Clicked="MaterialCard_Clicked">
<material:MaterialCard.GestureRecognizers>
<TapGestureRecognizer Command="{Binding CreateMQRCommand}" />
</material:MaterialCard.GestureRecognizers>
<Image Source="create_new_mqr.png"
Aspect="Fill"
HeightRequest="55"
WidthRequest="55"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand" />
</material:MaterialCard>
So I binded Opacity to property in my HomeViewModel.cs:
public double Opacity { get; set; } = 1;
Then, in CreateMQR method I'm trying to Change opacity just before navigating to another page.
private async void CreateMQR()
{
Opacity = 0.5;
await Task.Delay(700);
Opacity = 1;
ShowDialog();
await App.Current.MainPage.Navigation.PushAsync(new CreateMQRPage());
HideDialog();
}
Navigating works fine, command call method with no problem, opacity is set to values, but on screen nothing happen.
With opacity set on 0.5 and then back to 1, I want to create "blinking" effect on click. (Similar as buttons have)

Not knowing which Control MaterialCard inherite from .There is an sample about image ,maybe helpful to use.
XAML :
<Image x:Name="myimage" Source="icon.png">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"/>
</Image.GestureRecognizers>
</Image>
ContentPage :
private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{
Image image = sender as Image;
image.Opacity = 0;
image.FadeTo(1, 4000);
}
You can use Fading function to realize the animation when click it.

Related

Xamarin Forms CollectionView ScrollTo Not working on Load

I Have XAML form using a CollectionView. I bind the view to a collection of date objects. I set the SelectedItem in Code Behind which is working as expected. I then try to use ScrollTo in code behind however it always displays the first item in the collection once the page is loaded. After the page loads I have wired an image to fire the ScrollTo event and it works as expected. Below is my code. Thanks in advance for any help!
'''
for (int i = 0; i < 31 ; i++)
{
ScheduleDate date = new ScheduleDate();
date._Date = dt.AddDays(i);
colDates.Add(date);
}
cvDate.ItemsSource = colDates;
cvDate.SelectedItem = colDates[10];
cvDate.ScrollTo(cvDate.SelectedItem, null, ScrollToPosition.Start, true)
'''
XAML Form
'''
<CollectionView x:Name="cvDate" Grid.Row="0" Grid.Column="1"
SelectionMode="Single" >
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding Description}"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="Center"
/>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
'''
Edit:
I wired up the OnCollectionViewScrolled event and when the following line of code is executed from OnAppearing()
cvDate.ScrollTo(cvDate.SelectedItem, null, ScrollToPosition.Start, false);
OnCollectionViewScrolled is NOT being called. However when I execute the same line of code from a button click event OnCollectionViewScrolled is being fired.
I am not sure what is your Description and _Date. I make a simple example for your reference.
Trigger the ScrollTo in OnAppearing override method:
protected override void OnAppearing()
{
cvDate.ScrollTo(cvDate.SelectedItem, null, ScrollToPosition.Start, false);
}
Trigger the ScrollTo with button click method:
private void Button_Clicked(object sender, EventArgs e)
{
cvDate.ScrollTo(cvDate.SelectedItem, null, ScrollToPosition.Start, false);
}
The whole code:
public partial class Page4 : ContentPage
{
public ObservableCollection<ScheduleDate> colDates { get; set; }
public Page4()
{
InitializeComponent();
colDates = new ObservableCollection<ScheduleDate>();
for (int i = 0; i < 31; i++)
{
ScheduleDate date = new ScheduleDate();
date.Description = i.ToString();
colDates.Add(date);
}
cvDate.ItemsSource = colDates;
cvDate.SelectedItem = colDates[10];
}
protected override void OnAppearing()
{
cvDate.ScrollTo(cvDate.SelectedItem, null, ScrollToPosition.Start, false);
}
private void Button_Clicked(object sender, EventArgs e)
{
//cvDate.ScrollTo(cvDate.SelectedItem, null, ScrollToPosition.Start, false);
}
}
public class ScheduleDate
{
public string Description { get; set; }
}
Screenshot:
Update:
<ContentPage.Content>
<StackLayout>
<CollectionView
x:Name="cvDate"
ItemsSource="{Binding colDates}"
SelectionMode="Single">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Label
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
Text="{Binding Description}"
VerticalOptions="Center" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Button Clicked="Button_Clicked"></Button>
</StackLayout>
</ContentPage.Content>
I believe that at least on UWP you can't scroll to an element until it's actually been loaded by the UI.
In that case you could work around this with a CollectionView custom renderer.
You can override the ItemsViewRenderer.ScrollTo function and postpone the scroll until the target element has been loaded. To know when that happens you can register to the ListViewBase.ContainerContentChanging event.

WebView GestureRecognition not working in Xamarin forms

I have a webview When this webview is tapped I need to make visible of a button the problem Is Gesture recognition is not working
my Xaml
<customRenderer:CustomWebView Uri="{Binding SelectedJournal.Uri}" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" x:Name="CustomWebView" AbsoluteLayout.LayoutBounds="0,50,1,1" AbsoluteLayout.LayoutFlags="SizeProportional" >
<customRenderer:CustomWebView.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_OnTapped2" NumberOfTapsRequired="1" ></TapGestureRecognizer>
</customRenderer:CustomWebView.GestureRecognizers>
</customRenderer:CustomWebView>
<customRenderer:NavigationImageButton ItemTapped="FullScreenOnTapped" Source="full.jpg" AbsoluteLayout.LayoutBounds="0.5,1,-1,-1" AbsoluteLayout.LayoutFlags="PositionProportional" HeightRequest="60" WidthRequest="60" x:Name="FullScreenBtn" IsVisible="False" >
In the code behind i called like this
private void TapGestureRecognizer_OnTapped2(object sender, EventArgs e)
{
FullScreenBtn.IsVisible = true;
}
This should work but this is not working
also my custom rendering web view class
public class CustomWebView : WebView
{
public static readonly BindableProperty UriProperty = BindableProperty.Create<CustomWebView, string>(p => p.Uri, default(string));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
}
How to Achive this
Instead of using the gesture recognizer on your webview, you can use the 'Focused' event of your view to display your button. You can do something like this:
var wb = new WebView
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
Source = "https://stackoverflow.com/questions/56320611/webview-gesturerecognition-not-working-in-xamarin-forms",
};
wb.Focused += (s, e) =>
{
//Handle your logic here!
wb.Unfocus();
};
Here, Unfocus() is used if you wish to implement your logic everytime the webview is tapped.
A WebView is used in my application to display formatted text. Tapping the text should open an editor to modify the text. The suggested Focused event works on Android but not iOS (as of iOS 15.0 simulator at least). I found the solution in the comments for https://bugzilla.xamarin.com/42/42596/bug.html#c4. Adding an empty label to the xaml as a transparent overlay of the WebView registers the tap event and enables the gesture recogniser.
<Grid HeightRequest="132">
<WebView Grid.Column="0" Grid.Row="0"
Source="{Binding FormattedDescription, Converter={tr:StringToWebViewSourceConverter}}"
HeightRequest="132"/>
<Label Grid.Column="0" Grid.Row="0" Text=""
HeightRequest="132" HorizontalOptions="Fill">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding EditDescriptionCommand}"/>
</Label.GestureRecognizers>
</Label>
</Grid>

Disable ScrollView in Xamarin Forms without disabling buttons

I have the following XAML. I want to target phones with a scrollview, and want scrolling disabled on a tablet.
<ScrollView InputTransparent="False" Orientation="Both" >
<ScrollView.IsEnabled>
<OnIdiom x:TypeArguments="x:Boolean">
<OnIdiom.Phone>True</OnIdiom.Phone>
<OnIdiom.Tablet>True</OnIdiom.Tablet>
</OnIdiom>
</ScrollView.IsEnabled>
<StackLayout VerticalOptions="FillAndExpand" BackgroundColor="White" >
<StackLayout.HorizontalOptions>
<OnIdiom x:TypeArguments="LayoutOptions">
<OnIdiom.Tablet>FillAndExpand</OnIdiom.Tablet>
<OnIdiom.Phone>Start</OnIdiom.Phone>
</OnIdiom>
</StackLayout.HorizontalOptions>
<Grid BackgroundColor="White" HeightRequest="65" MinimumHeightRequest="65">
<Grid.HorizontalOptions>
<OnIdiom x:TypeArguments="LayoutOptions">
<OnIdiom.Tablet>CenterAndExpand</OnIdiom.Tablet>
<OnIdiom.Phone>Start</OnIdiom.Phone>
</OnIdiom>
</Grid.HorizontalOptions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<WebView x:Name="webViewBtn1" HeightRequest="65" Grid.Column="0" Grid.ColumnSpan="1" VerticalOptions="FillAndExpand" BackgroundColor="White">
<WebView.HorizontalOptions>
<OnIdiom x:TypeArguments="LayoutOptions">
<OnIdiom.Tablet>CenterAndExpand</OnIdiom.Tablet>
<OnIdiom.Phone>Start</OnIdiom.Phone>
</OnIdiom>
</WebView.HorizontalOptions>
<WebView.WidthRequest>
<OnIdiom x:TypeArguments="x:Double">
<OnIdiom.Tablet>770</OnIdiom.Tablet>
<OnIdiom.Phone>300</OnIdiom.Phone>
</OnIdiom>
</WebView.WidthRequest>
</WebView>
<Button Grid.Column="0" Grid.ColumnSpan="1" x:Name="btn1" Clicked="btn1_Clicked" BackgroundColor="Transparent" TextColor="Transparent" BorderColor="White" />
</Grid>
</StackLayout>
</ScrollView>
the buttons no longer allow the user to click on them if I set ScrollView.IsEnabled the following way:
<OnIdiom.Tablet>False</OnIdiom.Tablet>
My assumption that using InputTransparent was not correct. Is there a way to make the buttons clickable inside a scroll view that has scrolling disabled?
I essentially am looking for something like Orientation=None, but that is not an option.
You need to write a CustomRenderer for disabling the scroll.
On iOS UIScrollView has a ScrollEnabled property
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
// IsScrollEnabled just a custom property
// handled it in OnPropertyChanged too
ScrollEnabled = Element.IsScrollEnabled;
}
Android it is a bit tricky, there is not direct property. We intercept the touch event and return without handling it.
public override bool OnInterceptTouchEvent(MotionEvent ev)
{
if (Element.IsScrollEnabled)
{
return base.OnInterceptTouchEvent(ev);
}
else
{
return false;
}
}
public override bool OnTouchEvent(MotionEvent ev)
{
if (Element.IsScrollEnabled)
{
return base.OnTouchEvent(ev);
}
else
{
return false;
}
}
I ended up using this approach to disable vertical scrolling on an iPad, which is my target device. Not perfect for android 7 inch tablets, but oh well:
<ScrollView.Orientation>
<OnPlatform x:TypeArguments="ScrollOrientation">
<On Platform="iOS">
<OnIdiom x:TypeArguments="ScrollOrientation">
<OnIdiom.Phone>Both</OnIdiom.Phone>
<OnIdiom.Tablet>Horizontal</OnIdiom.Tablet>
</OnIdiom>
</On>
<On Platform="Android">
<OnIdiom x:TypeArguments="ScrollOrientation">
<OnIdiom.Phone>Both</OnIdiom.Phone>
<OnIdiom.Tablet>Both</OnIdiom.Tablet>
</OnIdiom>
</On>
<On Platform="UWP">Both</On>
</OnPlatform>
</ScrollView.Orientation>
In the latest version of Xamarin Forms, you can set the Orientation to Neither.
scrollV.Orientation = ScrollOrientation.Neither;
Cool and compact way to disable scrolling in Xamarin Forms without affecting it's children through ScrollEnabled extension method:
public static class ScrollViewEx
{
/// <summary>
/// Disables scrollview by modifying Scrolled Event and attaching itself to ScrollView's binding context
/// Scrolled event sends it back to the original x,y
/// </summary>
public class DisabledScrollClass : IDisposable
{
private double ScrollX;
private double ScrollY;
private object OldContext;
private ScrollView Parent;
public DisabledScrollClass(ScrollView parent)
{
Parent = parent;
ScrollX = parent.ScrollX;
ScrollY = parent.ScrollY;
OldContext = parent.BindingContext;
parent.Scrolled += Scrolled;
parent.BindingContext = this;
}
private void Scrolled(object sender, ScrolledEventArgs e)
{
(sender as ScrollView)?.ScrollToAsync(ScrollX, ScrollY, false);
}
public void Dispose()
{
Parent.Scrolled -= Scrolled;
Parent.BindingContext = OldContext;
}
}
public static ScrollView ScrollEnabled(this ScrollView scroll, bool isEnabled)
{
DisabledScrollClass binding = scroll.BindingContext as DisabledScrollClass;
if (isEnabled && binding != null)
binding.Dispose();
if (!isEnabled && binding == null)
_ = new DisabledScrollClass(scroll);
return scroll;
}
}

How to call IOS Custom render every time when I click a StackLayout(Having Gesture Recognizer) which is inside a ListView

I am trying to build a marquee for ios so I have written a custom Label render and used animation to achieve marquee and I am calling custom Label inside a stackLayout(stackLayout is inside a ViewCell of List). this StackLayout has a gesture Recogniser.
On click I want Marquee to get called every time so I can start and stop marquee on the gesture click.Renderer is not being called every time we click the view?
It only gets called when the ViewModel constructor is called. How do I make the renderer get called everytime I click on the gesture of Stack Layout. Below is the code I have tried.
Xaml Page:
<DataTemplate>
<ViewCell>
<StackLayout x:Name="MarqueeLabelGestureView" HorizontalOptions="FillAndExpand">
<controls:MarqueeLabelLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={x:Reference ResourceListView}, Path=BindingContext.OnMarqueeClicked}" CommandParameter="{Binding .}" />
</StackLayout.GestureRecognizers>
</StackLayout>
</ViewCell>
</DataTemplate>
Custom Render Code:
namespace VCS.FieldManager.UI.iOS.CustomRenderer
{
public class CustomLabelRender:LabelRenderer
{
public CustomLabelRender()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (Control != null)
{
UILabel marqueelabel = Control;
marqueelabel.Frame = new CGRect(40, 40, marqueelabel.Frame.X + 200, 40);
MessagingCenter.Send("", "OpenMarqueeLabel");
if (!GridEntryViewModel.isMarqueeClicked)
{
UIView.Animate(6, 0, UIViewAnimationOptions.CurveLinear| UIViewAnimationOptions.Repeat,
() =>
{
UIView.SetAnimationRepeatCount(1);
marqueelabel.Transform = CoreGraphics.CGAffineTransform.MakeTranslation(-100,0);
}, null);
// marqueelabel.Lines = 1200;
}
}
}
}
}

Crop image with rectangle

I have a Image and I want crop it by using a rectangle, code below is the code I put a image and draw a rectangle at middle of the image:
MainPage.Xaml:
<Canvas x:Name="canvas" HorizontalAlignment="Center" VerticalAlignment="Center" Width="340" Height="480" Background="Blue">
<Image x:Name="photo" HorizontalAlignment="Center" VerticalAlignment="Center" ManipulationMode="All">
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
<Path Stroke="Black" StrokeThickness="1">
<Path.Data>
<RectangleGeometry Rect="0,0,340,480"/>
</Path.Data>
</Path>
</Canvas>
I successful display the image and draw a rectangle. The sample image as below:
Now I want click a button to crop the image within the rectangle(not auto clip). The rectangle is auto added when image loaded. So cannot use "Point Pressed" and "Point Released". And also cannot use "rectangle.clip" because it will auto clip the image. How do I solve it? Thanks
Updated:
I able to move the image,How do I bind the data and set the rectangle coordinate to dynamic? Code below is to transform the image. Thanks.
public sealed partial class MainPage: Page
{
private CompositeTransform compositeTranslation;
public MainPage()
{
this.InitializeComponent();
photo.ManipulationDelta += Composite_ManipulationDelta;
compositeTranslation = new CompositeTransform();
photo.RenderTransform = this.compositeTranslation;
}
void Composite_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
// scale the image.
compositeTranslation.CenterX = photo.ActualWidth / 2;
compositeTranslation.CenterY = photo.ActualHeight / 2;
compositeTranslation.ScaleX *= e.Delta.Scale;
compositeTranslation.ScaleY *= e.Delta.Scale;
compositeTranslation.TranslateX += e.Delta.Translation.X;
compositeTranslation.TranslateY += e.Delta.Translation.Y;
}
}
I have not used or XAML as it creates confusion for me. So I created a snippet according to you problem. Try that and let me know the results. I have used the same image as you posted
XAML
<Page.BottomAppBar>
<AppBar IsSticky="True" IsOpen="True">
<Button Content="Crop" Click="btnCrop_Click" />
</AppBar>
</Page.BottomAppBar>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Image x:Name="photo" HorizontalAlignment="Center" VerticalAlignment="Center" ManipulationMode="All" Source="http://i.stack.imgur.com/UIBSp.png" />
<Path x:Name="path" Stroke="Red" StrokeThickness="3">
<Path.Data>
<RectangleGeometry Rect="545,212,440,420"/>
</Path.Data>
</Path>
</Grid>
C#
private void btnCrop_Click(object sender, RoutedEventArgs e)
{
var _rect = new RectangleGeometry();
_rect.Rect = path.Data.Bounds;
photo.Clip = _rect;
}