I have a tap event in my code. Its parent(not an immediate parent) also has tap event. In Android, everything works fine. But in ios, the event is propagating upwards to that parent. How to stop that event propagation (such as event.stopPropagation() in javascript).
Sample XML code:
<StackLayout tap="newsDetails" data-args="{{ $value }}">
<StackLayout orientation="horizontal" >
<Label text="Share" class="icon" tap="shareNews" data-args="{{ $value }}"/>
</StackLayout>
</StackLayout>
Note: I am using NativeScript core
Thank you.
You can use the boolean property isUserInteractionEnabled, however, this won't solve the issue as it will stop the user interaction for all nested elements as well. It is simply not good practice to have multiple tap events in the same area.
I had the same issue on android, here's a simple solution i came up with, not elegant but works :
private ignoreTap = false;
shareNews(){
this.ignoreTap = true;
// ...
}
newsDetails(){
if (this.ignoreTap) { this.ignoreTap = false; return; }
// ...
}
The flag ignoreTap will stop the root function execution.
Related
.net maui app.
Dragging value element along the slider bar does not work if the the slider put into CarouselView's template like this:
<CarouselView ItemsSource="{Binding Items}">
<CarouselView.ItemTemplate>
<DataTemplate>
<Slider Minimum="0" Maximum="30" WidthRequest="200" />
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
CarouselView takes over the swipe event for scrolling through the items, and Slider does not get the event (DragStarted is not even called). You can actually click along the slider bar to change its value, so it's not completely frozen, but not how it's supposed to work. Drag & drop is main way user deal with slider control.
Could anyone advise any workaround? I want users to be able scroll through carousel view items also. It's just if they swipe inside the control, event should not handed over to its parent container, if it's possible to do so.
If I add it outside of the corouselview, combine both in Grid and use padding to align slider inside the corouselview, it works as expected, but I need to add lots of additional code, calculate the desirable location and redirect all bindings, which ends up to be an awkward workaround.
At first, I don't suggest you use the slider in the CarouselView. Becasue you want the same behavior has two effects. There is a conflict between them.
But for the android, you can use the custom handler to deal with the swipe event.
Put the Handler class in the /Platform/Android:
public class MySliderHander : SliderHandler
{
protected override void ConnectHandler(SeekBar platformView)
{
base.ConnectHandler(platformView);
platformView.SetOnTouchListener(new SliderListener());
// the listener will make the slider deal with the swip event not the CarouselView.
}
}
Put the SliderListener class in the /Platform/Android
public class SliderListener : Java.Lang.Object, IOnTouchListener
{
public bool OnTouch(global::Android.Views.View v, MotionEvent e)
{
if (e.Action == MotionEventActions.Down || e.Action == MotionEventActions.Move)
{
v.Parent.RequestDisallowInterceptTouchEvent(true);
}
else
{
v.Parent.RequestDisallowInterceptTouchEvent(false);
}
return false;
}
}
And in the MauiProgram.cs:
builder
.UseMauiApp<App>()
.ConfigureMauiHandlers(handlers => {
#if ANDROID
handlers.AddHandler(typeof(Slider), typeof(YourProjectName.Platforms.Android.MySliderHander));
#endif
})
In addition, the Slider's height is same as the CarouselView. So you can use a frame to contain the Slider and swipe the CarouselView by swiping the frame.
I'm trying to find a way to remove the tab buttons on a element with an Angular 6 app but with no avail so far. Basically, I only want to keep the Tab contents and their swipe functionality.
Apparently there are specific android and iOS methods you can use but I'm unsure how to do that.
<TabView [(ngModel)]="tabSelectedIndex" (selectedIndexChanged)="onSelectedIndexChanged($event)" (loaded)="tabViewLoaded($event)">
<ng-container *ngFor="let article of articles" #tabView>
<StackLayout *tabItem="{title: article.id}">
<StackLayout>
<NewsDetails></NewsDetails>
</StackLayout>
</StackLayout>
</ng-container>
</TabView>
On my .ts file I can find a reference to the element like this:
#ViewChild("tabView") tabView: ElementRef;
ngAfterViewInit() {
console.dir(this.tabView.nativeElement);
}
But I have no idea what to do from now on. Any ideas? All previous questions regarding this have not worked.
Here is a sample playground link: https://play.nativescript.org/?template=play-ng&id=iK9ZTM
Use the code below with the loaded event of TabView.
onTabViewLoaded(event: EventData) {
const tabView = <TabView>event.object;
if (isIOS) {
tabView.viewController.tabBar.hidden = true;
}
if (isAndroid) {
const tabLayout = tabView.nativeViewProtected.tabLayout;
tabLayout.getLayoutParams().height = 0;
tabLayout.requestLayout();
}
}
I recently did that for a sample work I posted in Uplabs
I have added a GestureRecognizer like this:
faveLabel.Text = "ABC";
faveLabel.BackgroundColor = Color.Red;
faveLabel.GestureRecognizers.Add(new TapGestureRecognizer
{
Command = new Command(() => OnLabelClicked())
});
}
private void OnLabelClicked()
{
throw new NotImplementedException();
}
Here is the XAML:
<StackLayout Grid.Row="0" Grid.Column="0" Padding="15,10,20,10" HorizontalOptions="StartAndExpand" VerticalOptions="CenterAndExpand">
<Label x:Name="faveLabel" XAlign="Center" FontSize="23" />
</StackLayout>
Using the simulator it almost never works and when I did get it to work it seemed like I had to click above the text and not on the text. When I debug on my phone it works okay.
Are there some issues where the simulator does not respond correctly?
There are no issues that I know of. I haven't seen any weird myself unless I actually had something else causing it. You could try to give your Label a bright background color to see where it is actually positioned. Perhaps some of your other elements are overlapping it or something else in your UI is stopping the gesture recognizer. A common example is when you put one in a ListView which has a tap event of its own which might conflict with a TapGestureRecognizer.
How to hide a button, a label or a grid cell on iOS and show it on android, I have a xamarin.forms app (portable), I know that I have to use on platform but how to access the visibility of the controls.
Thanks
If you want to do it on XAML, in order to hide a view on a specific platform, you can use this:
<Button>
<Button.IsVisible>
<OnPlatform x:TypeArguments="x:Boolean"
iOS="false"
Android="true"/>
</Button.IsVisible>
</Button>
Hope it helps!
// IOS, Android, WP
SomeButton.IsVisible = Device.OnPlatform<bool>(false, true, true);
Or
if (Device.OS == TargetPlatform.Android)
{
SomeButton.IsVisible = true;
}
else
...
All of these answers seem to involve creating the control whether or not you actually need it and then setting IsVisible to false on the platforms you don't want it on. A better solution IMO is to only create the control in the first place if you do in fact need it. A first step would be to wrap it in a content view:
<ContentView>
<OnPlatform x:TypeArguments="View">
<OnPlatform.Android>
<Button Text="Something" ...etc... />
</OnPlatform.Android>
</OnPlatform>
</ContentView>
That's better, but it still creates a superfluous ContentView. Take it one step further and use OnPlatform to declare a ControlTemplate and you'll achieve the most optimal implementation across all platforms.
Like mindOfAi mentioned you can do this in XAML like this:
<Button>
<Button.IsVisible>
<OnPlatform x:TypeArguments="x:Boolean"
iOS="false"
Android="true"/>
</Button.IsVisible>
</Button>
In code you can use the Device.OnPlatform or check the Device.OS property.
That would look like:
// ... Other code here
Device.OnPlatform(iOS: () => { myButton.IsVisible = false; });
// Or do this:
if (Device.OS == TargetPlatform.iOS)
myButton.IsVisible = false;
// ... Other code here
From Xamarin.Forms version 2.5.x this is done as per code below. Using a basic button as an example.
<Button Text="NFC Pairing" Command="{Binding YourVmCommand}">
<Button.IsVisible>
<OnPlatform x:TypeArguments="x:Boolean">
<On Platform="iOS">true</On>
<On Platform="Android">false</On>
</OnPlatform>
</Button.IsVisible>
</Button>
Nigel
Expanding the solutions, you can also do xaml inline:
IsVisible="{OnPlatform iOS=true, Android=false}"
For anyone that stumbles upon this question seeking for the codebehind solution:
switch (Device.RuntimePlatform)
{
case Device.iOS:
//iOS specific code here
break;
case Device.Android:
//Android specific code here
break;
}
The Device class has the following Device constants:
Constants as shown from VS 2019 Intellisense.
HI for example below is my view
<ScrollView>
<StackLayout>
<StackLayout *ngFor="let kid of kids" id="kidList">
<StackLayout orientation="horizontal" class="some-class">
<Lable text="{{ kid.fname }} {{ kid.lname }}"></Lable>
<Lable text="{{ kid.age }} years ago"></Lable>
</StackLayout>
</StackLayout>
</StackLayout>
</ScrollView>
I want to append the more data getting from server to 'kidList' when scroll reaches to bottom of screen in {N} aAngular2.
It's very hard to me build the layouts and adding childs in 'js' like below(KidInformation has more data).
let stackLayout = new StackLayout();
stackLayout.addChild('something newly constructed with JS')
Is there a way we can do in My Component just by adding child as view by passing local parameters to view , I mean like in below way
let kidListStacklayout = view.getViewById(this.page, 'kidList');
kidListStacklayout.addChild('views/kid/kid-item.html')
and kid-item.html will look like
<StackLayout orientation="horizontal" class="some-class">
<Lable text="{{ kid.fname }} {{ kid.lname }}"></Lable>
<Lable text="{{ kid.age }} years ago"></Lable>
</StackLayout>
The stock list view supports what you want. Don't use a scrollview and adding more layouts to the screen. This will cause lag and other issues. A listview recycles UI view components to reduce overhead of the layout growing in size. You want to use the loadMore event on the list view. https://docs.nativescript.org/cookbook/ui/list-view
Of course as the comment above ^^^ the free UI suite from telerik provides the RadListView which also supports infinite scrolling with a loadMore event.
Find out how to do it ( using Angular & TypeScript) :
import { ScrollView, ScrollEventData } from "ui/scroll-view";
#Component({...})
class ComponentClass implements OnInit, AfterViewInit {
#ViewChild("scrollid") scrollView: ElementRef;
ngOnInit(){
let scrollv : ScrollView = <ScrollView>this.scrollView.nativeElement;
scrollv.on(ScrollView.scrollEvent, function (args: ScrollEventData) {
if(scrollv.scrollableHeight === args.scrollY){
console.log("load more items here !!! ");
}
});
}
}
The scrollv.scrollableHeight gets updated by itself.
Tested on android emulator only. Must work on both Plateforms.