Skip to content

Stacked Label elements doesn't pass-thru tap events (iOS) #3524

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
erjdriver opened this issue Jan 24, 2017 · 8 comments
Closed

Stacked Label elements doesn't pass-thru tap events (iOS) #3524

erjdriver opened this issue Jan 24, 2017 · 8 comments

Comments

@erjdriver
Copy link

Did you verify this is a real problem by searching Stack Overflow and the other open issues in this repo?

Yes..verified issue on iOS version of {N} only.

Tell us about the problem

I've got an AbsoluteLayout and in it I create a Label element. Then I've got another Label element stacked on top of it - it's wider and transparent background.

Label #1 has a tap event. Label #2 doesn't. I would like all taps on #1 to be called. Nothing for #2.

On iOS, looks like #2 is not passing thru the tap events.

Which platform(s) does your issue occur on?

iOS only.

Please provide the following version numbers that your issue occurs with:

  • CLI: (run tns --version to fetch it) 2.4.2

iOS platform 2.4.1

Please tell us how to recreate the issue in as much detail as possible.

Create an AbsoluteLayout. Create a label in it and register tap event. Create another label over it.

Now tap on label#1 - events not being called.

Is there code involved? If so, please share the minimal amount of code needed to recreate the problem.

@NickIliev
Copy link
Contributor

Hey @erjdriver

To prevent the label which is stacked on top to "steal" the tap you can use isUserInteractionEnabled boolean property and set it to false for your top label. This will not only dismiss all gestures for that label but will allow you to detect the gestures for the label positioned below in the visual stack.

For example:

page.xml

<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo">
    <AbsoluteLayout>
        <Label id="lbl1" text="This is Label 1" top="10" left="50" height="50" backgroundColor="green" tap="onTappedLabelOne" />
        <Label id="lbl2" text="This is Label 2" top="30" left="100" height="50" backgroundColor="yellow" isUserInteractionEnabled="false" />
    </AbsoluteLayout>
</Page>

page.ts

import { EventData } from 'data/observable';
import { Page } from 'ui/page';
import { Label } from "ui/label";

let page;

export function navigatingTo(args: EventData) {
    page = <Page>args.object;
}

export function onTappedLabelOne(args) {
    console.log("first label tapped!");

    var lbl = <Label>args.object;
    lbl.text += "ADD!";
}

Now tapping on label one (even if label two is in front of it) will always trigger.
The full sample project with the same property set from code-behind can be found here.

@erjdriver
Copy link
Author

My apologies - I forgot to mention that.

I tried it and it still didn't work. Though I tried it in code - not xml.

label2.isUserInteractionEnabled = false;

Again this problem is in iOS. It works on Android even w/o the above setting of isUserInteractionEnabled.

Since you took the trouble of testing it - I will go back and test it again.

p.s. i did notice that your coordinates for the 2 labels are not overlapping. What happens if you set label #2 coords to the same as that of #1.

@erjdriver
Copy link
Author

Actually - yes it does work!

Originally, I had entered the correct code but the taps were not registering on label #1 - but this was because of another {N} issue - which I think has been fixed in the upcoming release.

Thanks again.

@erjdriver
Copy link
Author

Interestingly, on Android platform - if you set the isUserInteractionEnabled to false - it doesn't pass thru any events.

@vjoao
Copy link
Contributor

vjoao commented Apr 14, 2017

@erjdriver have you been able to solve this consistently for both platforms?

@erjdriver
Copy link
Author

On iOS - i've got to set isUserInteractionEnabled to false explicitly.

It works without setting explicitly on the Android.

@mr-White
Copy link

mr-White commented Jul 26, 2018

I'm experiencing this issue right now. Works in Android, doesn't work in iOS.

What I've done is used the AbsoluteLayout to position a StackLayout on top of a GridLayout. The layer on top has a Slider which needs to be interactive and beneath it are labels that are tappable. You can swipe left/right the foreground layer to expose the menu items of the background layer from behind.

So I'm going to look into the isUserInteractionEnabled property of the View to be FALSE once the menu below (in the background layer) is exposed.

Kind of a bummer that I need to do this :/

Obviously, when the background menu is closed by either interaction or swipe, I need to set isUserInteractionEnabled to true otherwise, I suppose, the Slider of the foreground layer won't work anymore

PS originally I used the RadListView for the swiping to show the menus below, but when I enabled swiping, the ability to use the Slider stopped working. And not to confuse you, there are two swiping gestures in this UI. One to set the gauge of something and two to expose the background menu. Works in Android!

Update: Updated my code to turn on/off the isUserInteractionEnabled but it doesn't work for me :/ Does anyone have a solution for this?

My View code:

<StackLayout *ngFor="let feeling of feelings;let i = index" class="feeling-gauge-input-parent"> 
        <!-- Header: Emotion's name and emoticon representing sentimental score -->
        <AbsoluteLayout class="feeling-gauge-input">
            <!-- Background (menu) -->
            <GridLayout class="actions" rows="*" columns="auto, *, auto">
                <Label col="0" text="Remove" class="edit add-gutter" (tap)="deleteFeeling(i)"></Label>
                <Label col="1"></Label>
                <StackLayout col="2" class="edit">
                    <yf-sentiment-changer [(sentiment)]="feeling.sentiment"></yf-sentiment-changer>
                </StackLayout>
            </GridLayout>

            <!-- Foreground: Feeling Gauge/Sentiment Input -->
            <StackLayout class="feeling-gauge-input-container">
                <StackLayout orientation="horizontal" #panlayers (pan)="onFeelingHeadPan($event, i)" class="header add-gutter-hack">
                    <Label [text]="feeling.name | howMuchFeeling"></Label>
                    <yf-feeling-emoticon [sentiment]="feeling.sentiment" [gauge]="feeling.gauge"></yf-feeling-emoticon>
                </StackLayout>
            </StackLayout>
        </AbsoluteLayout>
        <!-- Footer: Scale to adjust the Feeling's gauge that directly effects opacity of above emoticon -->
        <Slider  
            minValue="0" maxValue="100" value="0" 
            [(ngModel)]="feeling.gauge" [ngModelOptions]="{standalone: true}" class="add-gutter gauge-slider"></Slider>
    </StackLayout>

What I was trying to do was on pan end, toggle the property, but even so, that won't be perfect for the UX because then the User won't be able to close the open menu without clicking an item or something :/

Some TS:

          // high up at the beginning of the class declaration
          @ViewChildren('panlayers') foregrounds:QueryList<StackLayout>;

          // somewhere in the pan handle function...... 
          if (isIOS) {
                if (destX !== 0) {
                    // we have opened the menu, let's freeze user interactions with the above layer
                    console.log('turn off isUserInteractionEnabled on foregrounds');
                    this.foregrounds.forEach((foreground) => {
                        foreground.isUserInteractionEnabled = false;
                    });
                } else {
                    // we closed the menu so let's return the normal functioning tap events to the above layer
                    console.log('turn on isUserInteractionEnabled on foregrounds');
                    this.foregrounds.forEach((foreground) => {
                        foreground.isUserInteractionEnabled = true;
                    });
                }
            }

Any tips would be greatly appreciated! Technically, the view in question, isn't visually covering the view from behind when it's exposed ? Even still, if we were to get this to work, it still won't be ideal UX :(

Anyone have luck integrating RadListView with swipe features while using a Slider in the ListView ?

Edit2:
Okay, I figured out the issue with isUserInteractionEnabled not working. First, I changed it to the parent element then I removed the ViewChildren reference in replace for a template 1-way data binding approach:

<!-- Foreground: Feeling Gauge/Sentiment Input -->
            <StackLayout class="feeling-gauge-input-container" [isUserInteractionEnabled]="swipeMenuesEnabled">
                <StackLayout orientation="horizontal" (pan)="onFeelingHeadPan($event, i)" class="header add-gutter-hack">
                    <Label [text]="feeling.name | howMuchFeeling"></Label>
                    <yf-feeling-emoticon [sentiment]="feeling.sentiment" [gauge]="feeling.gauge"></yf-feeling-emoticon>
                </StackLayout>
            </StackLayout>

See [isUserInteractionEnabled]="swipeMenuesEnabled" then in the pan function handler, I toggle the value. It's a step in the right direction, but now I can't close the background menues :/ haha

Open to suggestions!

Edit3: Found a way!
So in addition to Edit2.... I added the following code to the containing AbsoluteLayout:

(tap)="tapAbsoluteLayout()"

Then the function itself:

public tapAbsoluteLayout() {
        console.log('hi');
        if (! this.swipeMenuesEnabled) {
            console.log('enable me');
            this.swipeMenuesEnabled = true;
        } else {
            console.log('no change');
        }
    }

So if the menu is open, and swiping is disabled, we can enable it on tap which lets the gesture effect the foreground to swipe close to hide the background menues :)

Thank you @NickIliev for pointing out the isUserInteractionEnabled property!

Edit4: Making the new tap event for the AbsoluteLayout a pan event made it better. But still, the User has to tap/pan the area to enable interaction with the child element to swipe the menu closed. Once I figure a way around this, I'll post back. Currently, looking at using the position of the began pan gesture to see if it's not in the menu, then try to call the pan handling function immediately from there... we'll see!

@lock
Copy link

lock bot commented Aug 26, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked and limited conversation to collaborators Aug 26, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants