Nativescript: Suggestion: Changes to TabView in Android and more

Created on 20 Oct 2015  路  29Comments  路  Source: NativeScript/NativeScript

As TabHost is deprecated, is it possible to move tabs to ActionBar as Google recommends?

Can be TabView in Android based in fragments instead of ViewPager? or, at least have the option to choose how i want it: fragments or ViewPager; disable swiping?

I think you may match ViewPager in Android with UIPageViewController in iOS and build a dynamic carousel view that allow developer to add or remove child views.

question high

Most helpful comment

This is how i fix it:

tab-view.android.js line 31, insert this

var customViewPager = android.support.v4.view.ViewPager.extend({
    set swipeEnabled(value) { },
    //constructor
    init: function() {
        this.swipeEnabled = true;
    },
    onTouchEvent : function(event) {
        if (this.swipeEnabled) {
            return this.super.onTouchEvent(event);
        }
        return false;
    },
    onInterceptTouchEvent : function(event) {
        if (this.swipeEnabled) {
            return this.super.onInterceptTouchEvent(event);
        }
        return false;
    },
    setPagingEnabled : function(enabled) {
        this.swipeEnabled = enabled;
    }
});

then line 211 change this:

this._viewPager = new android.support.v4.view.ViewPager(this._context);

by this:

this._viewPager = new customViewPager(this._context);
this._viewPager.setPagingEnabled(false);

This should be part of {N} core. Adding swipeEnabled property to TabView and call setPagingEnabled using swipeEnabled as parameter.

All 29 comments

Hi @alexrainman , in the current version of {N} - 1.4.1, the tabs are neither in ActionBar, not in Toolbar, but in custom tab container. Do you have a specific functionality that you are not able to achieve with the current implementation of the components? And can you please provide more information about your scenario, so we can look more deep in the problem?

TabHost is based on TabActivity and TabActivity is deprecated. Google recommend the use of fragments and tabs navigation in the ActionBar/Toolbar.

What if i want the tabs in the ActionBar instead of TabHost?
What if i don't want swipe interaction between tabs?

That's what I'm expecting. That kind of flexibility.

For example, i added a RadListView to my first tab and i enabled swipe to execute functionality.

When i swipe, instead of swiping the ListView cell, i swipe to the next tab.

Another scenario (and this one is a real app i am working on):

What if i want multiple tabs and, inside of each tab, i want a CarouselView ( Android ViewPager / iOS UIPageViewController)?

I won't be able to achieve that with {N}.

@alexrainman Thanks for the feedback!
First of all let me clarify - for the TabView component in Android we use a ViewPager (for showing the content of the tabs) and a custom TabLayout (for showing the tab-items). The TabLayout component is implemented based on this example by google, but with some additional modifications that allow us to style the tabs. The code of this component lives here.

That said, form you posts, it looks like the main problem you are facing is that the TabView swallows the swipe events and prevents the default behavior of the controls inside it (RadListView, Carosel etc.). That is definitely something we will fix.

Are you facing other limitations of the TabView that are not related to the swipe gesture being handled incorrectly?

@vakrilov it seems in Android 5 ActionBar navigation options (like tabs) are deprecated so your solution seems to be the right one.

Anyway, the flexibility i mentioned before is still needed. Somehow you need to provide the option to disable swiping or make TabView based on simple fragments and not ViewPager.

This way, i can include content that need the swiping interaction on each tab: like list view or viewpager or maps, slider controls.

Thanks for your quick response.

I havent used the tabview, but when I tried the todo sample, I dont remember I can swipe to another tab, is the feature already available ? For IOS and Android ? With the bar animation on the tab title too ?

Swipe and animation is only available in Android. I just want the option to disable it and just get simple tabs that load different fragments when clicked. Actually, it will be good if both options are available.

Any news about this?

Hey @alexrainman , you can use this work-around to disable the swipe, until we expose a property, which will do the same:

if(tabView._viewPager) {
        var listener = new android.view.View.OnTouchListener({
            onTouch: function (view, event) {
                page.backgroundColor = "red";
                return true;
            }
        });
        tabView._viewPager.setOnTouchListener(listener);
    }

Another option is to use the SegmentedBar and avoid the problem with the swipe.

@N3ll i will use this code to disable swiping on Android. Thanks.

About SegmentedBar, i have an idea that can be useful to make SegmentedBar look and behave the same across platforms. I will share it once it's ready using another thread. Thanks.

Question: how do i get TabView instance when i use xml?

I found the way to get TabView instance and i was able to test your code snippet too. It works. Now i am able to disable swiping in the ViewPager but, the issue still there.

If i include something that needs swiping interaction inside one of the tabs, like RadListView cell actions, the previous overrided event swallows the RadListView cell swiping event and instead, the tabview swipes a little bit and starts showing a piece of the next tab :(

Please, provide a way to have TabView widget not based in Android ViewPager.

Android is pretty flexible and allows you to do things in multiple ways. That's the case of tabs. You can have the swiping event you guys provide or you can have only tabs that, when clicked, will load a fragment in a container.

I think you may provide both and allow me to choose which one i want to use.

In the case of SegmentedBar, you are using TabHost in Android and i think that's confusing. I have some code i used before that creates a SegmentedBar with exact the same behavior as iOS version. It's based on radio group and it works nice. I want to fork {N} and incorporate it and ask you guys to review it.

Thanks.

I agree with alexrainman about SegmentedBar

@x4080 +1

@N3ll you can use this one as reference to implement SegmentedBar in Android with iOS look and feel: https://github.com/hoang8f/android-segmented-control

@alexrainman - this looks great! We will surely consider it!

@N3ll @valentinstoychev Awesome!

@N3ll but please, provide what i need for TabView :+1:

@alexrainman
We have researched the topic more deeply found a solution for the view-pager-stealing-events problem. It is based on this blog post. Here is how it look like in native script (you will need to set id-s for the tab-view and the list-view)

var tabView = page.getViewById("tab-view-id");
var list = page.getViewById("list-view-id");

if (tabView._viewPager) {
    var pager = tabView._viewPager;
    var list = list.android;

    var listListener = new android.view.View.OnTouchListener({
        onTouch: function (view, event) {
            var ac = event.getAction() & android.view.MotionEvent.ACTION_MASK;
            pager.requestDisallowInterceptTouchEvent(true);
            if (ac === android.view.MotionEvent.ACTION_UP) {
                pager.requestDisallowInterceptTouchEvent(false);
            }
            return false;
        }
    });

    list.setOnTouchListener(listListener)
}

I hope that works well in your app.

Then, you won't provide an optional way for TabView widget not based on ViewPager? I will try this fix anyway. Thanks

Actually, it needs to be this way to completelly disable TabView swiping in Android and enable a widget with swipe interactions, like RadListView, inside one of the tabs:

    var tabView = page.getViewById("tabView");
    var list = page.getViewById("radList");

    if(tabView._viewPager) {

        var tabListener = new android.view.View.OnTouchListener({
            onTouch: function (view, event) {
                return true;
            }
        });

        tabView._viewPager.setOnTouchListener(tabListener);

        var pager = tabView._viewPager;
        var list = list.android;

        var listListener = new android.view.View.OnTouchListener({
            onTouch: function (view, event) {
                var ac = event.getAction() & android.view.MotionEvent.ACTION_MASK;
                pager.requestDisallowInterceptTouchEvent(true);
                if (ac === android.view.MotionEvent.ACTION_UP) {
                    pager.requestDisallowInterceptTouchEvent(false);
                }
                return false;
            }
        });

        list.setOnTouchListener(listListener)

    }

@alexrainman You are correct - you code will completely disable the swipe. I was looking for as solution that will still allow you to swipe outside the list-view and change tabs.

About your suggestion of ViewPager-free implementation of TabView: currently, we prefer to concentrate on fixing issues (like the one with the swipe) with the existing implementation (with ViewPager) than to re-implement the whole component.

That said your suggestion is not out of question so we will consider it. If you decide to implement it yourself - publishing a native-script plugin would be a great way to share it with the community.

I have two plugins to go. I think SimpleTabView will go first, then PageSlider. I will keep you posted guys. Thanks.

solution

    if(tabView._viewPager) {
        var listener = new android.view.View.OnTouchListener({
            onTouch: function (view, event) {
                return true;
            }
        });
        tabView._viewPager.setOnTouchListener(listener);
    }

does not seem to work anymore :/
It swipes 20 Pixels then it stucks.
For any swipe you make it goes about 20px further so you see two tabViewElements partially at the same time.
Disabling the swipe seems to be complicated even on the native platform:
http://stackoverflow.com/questions/13169635/disable-swiping-between-tabs-in-fragmentactivity/13328606#13328606
Any news to this?

screenshot_20160707-111543

This solution is not working anymore. How i can disable swiping between tabs in Android?

This is how i fix it:

tab-view.android.js line 31, insert this

var customViewPager = android.support.v4.view.ViewPager.extend({
    set swipeEnabled(value) { },
    //constructor
    init: function() {
        this.swipeEnabled = true;
    },
    onTouchEvent : function(event) {
        if (this.swipeEnabled) {
            return this.super.onTouchEvent(event);
        }
        return false;
    },
    onInterceptTouchEvent : function(event) {
        if (this.swipeEnabled) {
            return this.super.onInterceptTouchEvent(event);
        }
        return false;
    },
    setPagingEnabled : function(enabled) {
        this.swipeEnabled = enabled;
    }
});

then line 211 change this:

this._viewPager = new android.support.v4.view.ViewPager(this._context);

by this:

this._viewPager = new customViewPager(this._context);
this._viewPager.setPagingEnabled(false);

This should be part of {N} core. Adding swipeEnabled property to TabView and call setPagingEnabled using swipeEnabled as parameter.

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.

Was this page helpful?
0 / 5 - 0 ratings