Disable click event on clipped area from cornered button - xamarin.forms

I have created a button and added pressed event on it. The button height and width are 300x300 and the corner radius is 150. So it looks like circle.
<Button
WidthRequest="300"
HeightRequest="300"
BackgroundColor="Red"
VerticalOptions="Center"
Margin="20,0,20,0"
HorizontalOptions="CenterAndExpand"
CornerRadius="150">
<Button.Behaviors>
<behaviors:EventToCommandBehavior EventName="Pressed"
Command="{Binding ButtonPressedCommand}" />
</Button.Behaviors>
</Button>
The issue is when I click blue area it cahtches pressed event. I want blue area to not catch the event. Now it detects the button as square, not as circle.

Broadly speaking, you shouldn't do that. The touch input is imprecise and unless your button is particularly huge those blue areas on your pic are within the bounds of the imprecise measurement and as such should be treated in that way.
If you really need this, you may try with MR.Gestures.AbsoluteLayout. Here is an example where it provides the exact point that the user has tapped: https://devtut.github.io/xamarin/gestures.html#place-a-pin-where-the-user-touched-the-screen-with-mr-gestures

For iOS, you can create a custom class which inherites UIButton and override the method PointInside.
class CustomiOSButton : UIButton
{
public override bool PointInside(CoreGraphics.CGPoint point, UIKit.UIEvent uievent)
{
bool flag = base.PointInside(point, uievent);
if (flag)
{
UIBezierPath path = UIBezierPath.FromOval(this.Bounds);
if (path.ContainsPoint(point))
{
return true;
}
}
return false;
}
}

Related

Xamarin forms: Top stacklayout is not visible in UI when keyboard is on

My Xaml:
<StackLayout
Orientation="Vertical">
<StackLayout
Orientation="Horizontal">
//Group labels and back arrow
</StackLayout>
<ListView>
//Message list
</ListView>
<Grid>
//Plus symbol,Editor and send icon
</Grid>
</StackLayout>
Screenshot:
Issue:
In normal screen there is a bar on the top(red circled). When click the editor on the bottom top bar is hiding. I need the top bar always on top. This issue is only in IOS part, in android this feature is working fine. How can I fix this issue?
Its an iOS feature that the UI is adjusted upwards. You can shrink (or keep) the view via a custom renderer.
Check this great explanation.
And also this peace of code for a keyboard custom renderer on iOS.
Like the picture in the question my soft keyboard always touching the Editor. So I added a custom renderer for my Editor to solve that issue. After adding that custom renderer the top bar is always sticking on the top of the page.
I used the following custom renderer to solve the keyboard overlapping issue:
using System;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using HBIClientFacingApp;
using HBIClientFacingApp.iOS;
[assembly:ExportRenderer( typeof(CustomEditor), typeof(CustomEditorRenderer))]
namespace YourNameSpace.iOS
{
public class CustomEditorRenderer: EditorRenderer
{
public ChatEntryRenderer()
{
UIKeyboard.Notifications.ObserveWillShow ((sender, args) => {
if (Element != null)
{
Element.Margin = new Thickness(0,0,0, args.FrameEnd.Height); //push the entry up to keyboard height when keyboard is activated
}
});
UIKeyboard.Notifications.ObserveWillHide ((sender, args) => {
if (Element != null)
{
Element.Margin = new Thickness(0); //set the margins to zero when keyboard is dismissed
}
});
}
}
}

How can I achieve dragging on frame within Absolutelayout

I have a frame in absolutelayout as shown below. I would like that user to be able drag and relocate this frame on the screen. I tried to implement a pan gesture but unfortunately it doesnt work as expected. Can somebody show me the correct way? Is it possible without using any 3rd party library?
<AbsoluteLayout>
<Frame x:Name="frm" Padding="1" AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0.5,0,0.3,0.3" IsVisible="{Binding IsSmallTimerVisible}" >
<Frame.GestureRecognizers>
<PanGestureRecognizer PanUpdated="OnPanUpdated" />
</Frame.GestureRecognizers>
<shared:_customControl/>
</Frame>
Grid VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1">
<Grid.RowDefinitions>
<RowDefinition Height="0.1*" />
<RowDefinition Height="0.3*" />
<RowDefinition Height="2.5*" />
</Grid.RowDefinitions>
And in the code behind
double x, y;
private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
switch (e.StatusType)
{
case GestureStatus.Running:
// Translate and ensure we don't pan beyond the wrapped user interface element bounds.
Content.TranslationX =
Math.Max(Math.Min(0, x + e.TotalX), -Math.Abs(Content.Width - App.ScreenWidth));
Content.TranslationY =
Math.Max(Math.Min(0, y + e.TotalY), -Math.Abs(Content.Height - App.ScreenHeight));
break;
case GestureStatus.Completed:
{
// Store the translation applied during the pan
x = Content.TranslationX;
y = Content.TranslationY;
AbsoluteLayout.SetLayoutBounds(frm, new Rectangle(x, y, .3, .3));
break;
}
}
}
Seem like what you need is a Touch Tracking Effect
This example is very similar with your requirement.
void OnTouchEffectAction(object sender, TouchActionEventArgs args)
{
BoxView boxView = sender as BoxView;
switch (args.Type)
{
case TouchActionType.Pressed:
// Don't allow a second touch on an already touched BoxView
if (!dragDictionary.ContainsKey(boxView))
{
dragDictionary.Add(boxView, new DragInfo(args.Id, args.Location));
// Set Capture property to true
TouchEffect touchEffect = (TouchEffect)boxView.Effects.FirstOrDefault(e => e is TouchEffect);
touchEffect.Capture = true;
}
break;
case TouchActionType.Moved:
if (dragDictionary.ContainsKey(boxView) && dragDictionary[boxView].Id == args.Id)
{
Rectangle rect = AbsoluteLayout.GetLayoutBounds(boxView);
Point initialLocation = dragDictionary[boxView].PressPoint;
rect.X += args.Location.X - initialLocation.X;
rect.Y += args.Location.Y - initialLocation.Y;
AbsoluteLayout.SetLayoutBounds(boxView, rect);
}
break;
case TouchActionType.Released:
if (dragDictionary.ContainsKey(boxView) && dragDictionary[boxView].Id == args.Id)
{
dragDictionary.Remove(boxView);
}
break;
}
}
The Pressed logic sets the Capture property of the TouchEffect object
to true. This has the effect of delivering all subsequent events for
that finger to the same event handler.
The Moved logic moves the BoxView by altering the LayoutBounds
attached property. The Location property of the event arguments is
always relative to the BoxView being dragged, and if the BoxView is
being dragged at a constant rate, the Location properties of the
consecutive events will be approximately the same. For example, if a
finger presses the BoxView in its center, the Pressed action stores a
PressPoint property of (50, 50), which remains the same for subsequent
events. If the BoxView is dragged diagonally at a constant rate, the
subsequent Location properties during the Moved action might be values
of (55, 55), in which case the Moved logic adds 5 to the horizontal
and vertical position of the BoxView. This moves the BoxView so that
its center is again directly under the finger.
You can move multiple BoxView elements simultaneously using different
fingers.

How to handle the mouse wheel scrolling event using JavaFX?

Just need to get some numeric equivalent, which will show how much the wheel is scrolled.
I managed to find an example only using awt/swing: Java Docs
P.S. Sorry for my English.
{
...
sceneChart.setOnScroll(event -> print(event));
}
public void print (ScrollEvent event) {
System.out.println(event.getDeltaY());
}
add onScroll to your javafx element to handle scroll event
for example here add onScroll to ImageView
<ImageView onScroll="#onScrollImageView" .........../>
and handle that in fxml controller like here:
public void onScrollImageView(ScrollEvent scrollEvent) {
double deltaY = scrollEvent.getDeltaY();
if(deltaY<0)
//scroll up
if(deltaY>0)
//scroll down
}
getDeltaY() return the vertical scroll amount.
and negative value of getDeltaY() or positive value means scroll direction

Xamarin.Forms: ListView inside StackLayout: How to set height?

In a ContentPage I have a ListView inside a StackLayout inside a ScrollView. The ListView is populated (ItemSource is set) in the ContentPage when OnAppearing gets called and I can see that the list is populated in the emulator. The StackLayouts orientation is Vertical and below the ListView I have a Button.
My problem is that no matter how many elements the ListView has, it gets the height of 53.33. I would like the height of the ListView to match the total height of the items in it. By setting HeightRequest I can set the height of the ListView to anything I want, but since I do not know the height of the items inside the ListView the result is most often that the distance to the button below it is incorrect and therefore looks ugly. I have tried to set VerticalOptions on both the ListView and the StackLayout to Startand other settings, but this does not change the height from 53.33 (and if I try to combine using HeightRequest and Start it turns out that HeightRequest wins out).
How can I solve this?
(please excuse the cross posting from Xamarin forum)
With the new BindableLayout feature in Xamarin Forms 3.5 you can easily use the ItemsSource on StackPanel.
So, basically you can write something like this:
<StackLayout BindableLayout.ItemsSource="{Binding list}">
<BindableLayout.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
You can read more about it here: https://blog.xamarin.com/xamarin-forms-3-5-a-little-bindable-love/
The solution in my case was to put the ListView inside a StackLayout and then put that StackLayout inside the main StackLayout. Then I could set the VerticalOptions = LayoutOptions.FillAndExpand on the inner StackLayout (the one containing the ListView) with the result that the ListView got the space it needed (which of course varies depending on the data).
Here is the main code:
listView.ItemsSource = alternativeCells;
listView.ItemSelected += ListViewOnItemSelected;
var listStackLayout = new StackLayout
{
VerticalOptions = LayoutOptions.FillAndExpand,
Orientation = StackOrientation.Vertical
};
listStackLayout.Children.Add(listView);
_stackLayout.Children.Add(listStackLayout);
As you see, I added a new StackLayout with the only purpose of putting the ListView inside it. Then I put that listStackLayout inside the main _stackLayout.
See the post on this Xamarin forum post for more information
I ran into the same problem, and for me this worked like a charm:
listView.HasUnevenRows = true;
(http://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/listview/#Display_Rows_with_Variable_Heights)
I had the same problem, and this was the only thing I did that solved for me (in XAML):
<StackLayout Orientation="Vertical"
VerticalOptions="Fill"
HorizontalOptions="StartAndExpand">
<ListView VerticalOptions="FillAndExpand"
RowHeight="<some row height>">
</ListView>
</StackLayout>
Hope it works!
Below code worked for me,
protected override void OnAppearing()
{
base.OnAppearing();
listViewOrderCloths.HeightRequest = model.ListOrderedCloths.Count*100)/2 ;
}
I had a similar struggle, with a slightly different solution. First, setting a RowHeight on the ListView seemed to be pivotal. Second, I was running into a binding + timing issue. If the ListView was displayed and had no contents, it was set to a default height (showing the empty space). If I moved away from this page and came back, the size was fine.
So my approach was to bind the ListView's visibility to the presence (or lack of) something being bound to. Then when data came back, the ListView became visible and had the proper size.
<ListView x:Name="lvSettlements" ItemsSource="{Binding RecentSettlements}" VerticalOptions="FillAndExpand" RowHeight="25" IsVisible="{Binding RecentSettlements, Converter={StaticResource nullConverter}}">
...SNIP...
</ListView>
On Android, my table created in code was leaving gaps above and below it.
This fixed it...
HeightRequest="1000000"
I think I have the hackiest solution.
The accepted answer wasn't applicable to my situation, where my ListView might be longer then the length of the display, hence it needs be placed within a ScrollView, which brings back the empty space.
They way I solved this, was to have top level StackLayout and then place the ListView in an immediate ScrollView, like the following XAML:
<?xml version="1.0" encoding="utf-8" ?>
<local:ContentPage>
<StackLayout x:Name="entirePage">
<ScrollView VerticalOptions="FillAndExpand"
Orientation="Vertical">
<ListView x:Name="listView" ItemsSource="{Binding Items}"
Margin="0">
<!-- ListView Stuff -->
</ListView>
</ScrollView>
</StackLayout><!--entirePage-->
</local:ContentPage >

show border on rollover and select the thumb on click and unselect pre selected thumb

I have some small canvas, and i have to show border around them, i did that using rollover and rollout evenets, (these canvas hold product images), here rollover and rollout are working perfectly fine, but when a user clicks on some canvas, it has to be selected, means it has show the border around it, and rest canvas should work as normal. but when i select another canvas the previously selected canvas should get unselected and new clicked canvas gets the selection,
but the problem which is coming the rollOut event which is applied on canvas, on a click the canvas get selected, but when rollOut takes place it unselect the canvas, i even removed the rollOut listner on the click of a canvas, but in that case, the clicked canvas will not get unselected , when other canvas will be clicked
can.addEventListener(MouseEvent.ROLL_OVER,onRollOverThumb);
can.addEventListener(MouseEvent.ROLL_OUT,onRollOutThumb);
//can.addEventListener(MouseEvent.CLICK,onRollOverThumb);
private function onRollOverThumb(event:MouseEvent):void
{
event.target.setStyle('borderColor','0x000000');
event.target.setStyle('borderThickness','3');
event.target.setStyle('borderStyle','solid');
}
private function onRollOutThumb(event:MouseEvent):void
{
event.target.setStyle('borderColor','0xCCCCCC');
event.target.setStyle('borderThickness','1');
event.target.setStyle('borderStyle','solid');
}
i hope some thing are clear in this, does n e one has worked on this, please reply
Thanks in advance
Ankur sharma
What about implementing a "flag" variable that is set to true when the click occurs. Then, when the ROLL_OUT occurs, check if the flag is true or false. If true, don't do anything, if false, remove/change the border.
private function onRollOverThumb(event:MouseEvent):void
{
if(event.type=='click')
{
for(var j:int=0;j<viewparent.numChildren;j++)
{
viewparent.getChildAt(j).name="false";
}
event.currentTarget.name="true";
for(var i:int=0;i<viewparent.numChildren;i++)
{
if(viewparent.getChildAt(i).name=="true")
{
Canvas(viewparent.getChildAt(i)).setStyle('borderColor','0x000000');
Canvas(viewparent.getChildAt(i)).setStyle('borderThickness','3');
Canvas(viewparent.getChildAt(i)).setStyle('borderStyle','solid');
}
else
{
Canvas(viewparent.getChildAt(i)).setStyle('borderColor','0xCCCCCC');
Canvas(viewparent.getChildAt(i)).setStyle('borderThickness','1');
Canvas(viewparent.getChildAt(i)).setStyle('borderStyle','solid');
}
}
}
else
{
event.currentTarget.setStyle('borderColor','0x000000');
event.currentTarget.setStyle('borderThickness','3');
event.currentTarget.setStyle('borderStyle','solid');
}
}
private function onRollOutThumb(event:MouseEvent):void
{
if(event.currentTarget.name=="false")
{
event.currentTarget.setStyle('borderColor','0xCCCCCC');
event.currentTarget.setStyle('borderThickness','1');
event.currentTarget.setStyle('borderStyle','solid');
}
}
i modified my own code, added one name property to the canvases
can.name="false"
and it's now working,
can n e one tell me, how to put some select and unselect(kind of fade effect) on the border, when the black selection get removed, it shld be removed in some fade manner, can we apply fade effect on border?

Resources