3

I have the following ViewPager's FINANCIAL fragment page.

enter image description here

It is built using the following mythology

this.detailedStockFragmentPagerAdapter = new DetailedStockFragmentPagerAdapter(this.getSupportFragmentManager(), bundle);
viewPager.setAdapter(detailedStockFragmentPagerAdapter);
viewPager.setOffscreenPageLimit(Math.max(1, detailedStockFragmentPagerAdapter.getCount() - 1));
tabLayout.setupWithViewPager(viewPager);

private static class DetailedStockFragmentPagerAdapter extends FragmentPagerAdapter {
    public DetailedStockFragmentPagerAdapter(FragmentManager fm, Bundle bundle) {
        super(fm);
        this.bundle = bundle;
    }

    @Override
    public int getCount() {
        return 3;
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
            {
                ...
            }
            case 1:
            {
                ...
            }
            case 2:
            {
                FinancialFragment financialFragment = FinancialFragment.newInstance();
                financialFragment.setArguments(bundle);
                return financialFragment;
            }
            default:
                assert(false);
        }
        return null;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        switch (position) {
            case 0:
                return JStockApplication.instance().getString(R.string.info);
            case 1:
                return JStockApplication.instance().getString(R.string.news);
            case 2:
                return JStockApplication.instance().getString(R.string.financial);
            default:
                return null;
        }
    }
}

In FINANCIAL page, there are 3 components

  1. Button
  2. TextView
  3. inner TabLayout (The bar with 1D, 1W, 1M, 3M, ...)

If I touch any of the following components, and swipe toward right, it works as expected.

  1. Button
  2. TextView
  3. Any empty area of the fragment

enter image description here


However, if my touch area is inner TabLayout, swipe doesn't work. It seems that the TabLayout has "eaten" my swipe event.

Any idea how I can have inner TabLayout in ViewPager fragment, yet doesn't affect my swipe event?

The XML of my ViewPager fragment page is as follow

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:layout_marginBottom="20dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is button"
        android:textSize="18sp" />

    <TextView
        android:layout_marginBottom="20dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#ff000000"
        android:textSize="18sp"
        android:text="This fragment is not scrollable. How to make toolbar visible?"/>

    <LinearLayout
        android:id="@+id/period_tablayout_linear_layout"
        android:layout_width="match_parent"
        android:layout_height="38dp"
        android:orientation="vertical">

        <android.support.design.widget.TabLayout
            android:id="@+id/period_tab_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"

            app:tabTextAppearance="@style/TradingChartPeriodTabTextAppearance"
            app:tabPaddingStart="0dp"
            app:tabPaddingEnd="0dp"
            app:tabIndicatorHeight="2dp"
            app:tabMode="fixed"
            app:tabGravity="fill"
            app:tabBackground="?attr/tradingHistorySummaryChartBackgroundColor"
            app:tabSelectedTextColor="?attr/primaryTextColor"
            app:tabIndicatorColor="?attr/primaryTextColor">

            <android.support.design.widget.TabItem
                android:id="@+id/tab_item_1d"
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:text="@string/trading_day_1_short" />

            <android.support.design.widget.TabItem
                android:id="@+id/tab_item_1w"
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:text="@string/trading_week_1_short" />

            <android.support.design.widget.TabItem
                android:id="@+id/tab_item_1m"
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:text="@string/trading_month_1_short" />

            <android.support.design.widget.TabItem
                android:id="@+id/tab_item_3m"
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:text="@string/trading_months_3_short" />

            <android.support.design.widget.TabItem
                android:id="@+id/tab_item_6m"
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:text="@string/trading_months_6_short" />

            <android.support.design.widget.TabItem
                android:id="@+id/tab_item_1y"
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:text="@string/trading_year_1_short" />

            <android.support.design.widget.TabItem
                android:id="@+id/tab_item_5y"
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:text="@string/trading_years_5_short" />

            <android.support.design.widget.TabItem
                android:id="@+id/tab_item_10y"
                android:layout_height="wrap_content"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:text="@string/trading_period_max" />

        </android.support.design.widget.TabLayout>

    </LinearLayout>

</LinearLayout>
azizbekian
  • 60,783
  • 13
  • 169
  • 249
Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875

3 Answers3

2

TabLayout is a subclass of HorizontalScrollView, which in turn is a subclass of ScrollView. If you disable horizontal scrolling, then the MotionEvent won't be swallowed by TabLayout, instead would be passed higher up the view hierarchy - to ViewPager.

You can subclass TabLayout performing following changes:


    public class MyTabLayout extends TabLayout {

        public MyTabLayout(Context context) {
            super(context);
        }

        public MyTabLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        public MyTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }

        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    return false;
                default:
                    return super.onTouchEvent(ev);
            }
        }

        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            return false;
        }

    }

Output:

enter image description here

azizbekian
  • 60,783
  • 13
  • 169
  • 249
  • Hi @azizbekian, you disabled the scroll for tab on ACTION_DOWN event, this will also disable the vertical scroll of tablayout. – Amit Bhati Oct 05 '17 at 13:31
  • @AmitBhati, `TabLayout` does not have vertical scrolling, neither OP needs it in his use case. – azizbekian Oct 05 '17 at 13:32
  • TabLayout may contains child fragment that may contains any scrollview – Amit Bhati Oct 05 '17 at 13:35
  • @Amit Bhati, I'm not sure that's possible to do. Judging by [docs](https://developer.android.com/reference/android/support/design/widget/TabLayout.html), `TabLayout` expects only a `TabItem`. Nevertheless, if you apply [this](https://stackoverflow.com/a/40897198/1083957) approach, then judging by [sources of `TabView#onMeasure()`](https://android.googlesource.com/platform/frameworks/support/+/master/design/src/android/support/design/widget/TabLayout.java#1583), there are **no** constraints on `heightMeasureSpec`, scrollview should be completely laid out. – azizbekian Oct 05 '17 at 14:12
  • I think that my solution takes care of these cases and should be the accepted one – Antonis Lat Oct 06 '17 at 10:11
0

I think the following works:

public class CustomTabLayout extends TabLayout {
    private PointF touchStartPoint;
    private int mTouchSlop;
    private boolean mIsScrolling;

    public CustomTabLayout(Context context) {
        super(context);
        config();

    }

    public CustomTabLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        config();
    }

    public CustomTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        config();

    }

    private void config() {
        ViewConfiguration vc = ViewConfiguration.get(getContext());
        mTouchSlop = vc.getScaledTouchSlop();
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();

        if (action == MotionEvent.ACTION_DOWN) {
            touchStartPoint = new PointF(ev.getX(), ev.getY());

            return super.onInterceptTouchEvent(ev);
        }

        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {

            mIsScrolling = false;
            return false;
        }

        switch (action) {
            case MotionEvent.ACTION_MOVE: {
                if (mIsScrolling) {
                    return false;
                }
                final int xDiff = calculateDistanceX(ev);
                if (xDiff > mTouchSlop) {
                    mIsScrolling = true;
                    return true;
                }
                break;
            }
        }
        return super.onInterceptTouchEvent(ev);
    }

    private int calculateDistanceX(MotionEvent ev) {
        return (int) Math.abs(ev.getX() - touchStartPoint.x);
    }
}
Antonis Lat
  • 545
  • 4
  • 9
-1

you can use Viewpager inside your FinantialFragment After Changing Your FinancialFragment should be like below :

public class FinancialFragment extends Fragment {

    private ViewPager viewPager;
    private View rootView;
    private TabLayout tabLayout;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment

        rootView = inflater.inflate(R.layout.fragment_three, container, false);
        viewPager = (ViewPager) rootView.findViewById(R.id.viewpager);
        tabLayout = (TabLayout) rootView.findViewById(R.id.period_tab_layout);

        return rootView;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);


        setupViewPager(viewPager);

        tabLayout.setupWithViewPager(viewPager);

    }

    private void setupViewPager(ViewPager viewPager) {
        ViewPagerAdapters adapter = new ViewPagerAdapters(getChildFragmentManager() );
        adapter.addFragment(new OneDayFragment(), "1D");
        adapter.addFragment(new OneWeekFragment(), "1W");
        adapter.addFragment(new OneMonthFragment(), "1M");
        adapter.addFragment(new ThreeMonthFragment(), "3M");
        adapter.addFragment(new SixMonthFragment(), "6M");
        adapter.addFragment(new OneYearFragment(), "1Y");
        adapter.addFragment(new FiveYearFragment(), "5Y");
        viewPager.setAdapter(adapter);
        viewPager.setOffscreenPageLimit(Math.max(1, adapter.getCount() - 1));
    }

    class ViewPagerAdapters extends FragmentPagerAdapter {
        private final List<Fragment> mFragmentList = new ArrayList<>();
        private final List<String> mFragmentTitleList = new ArrayList<>();

        public ViewPagerAdapters(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return mFragmentList.get(position);
        }

        @Override
        public int getCount() {
            return mFragmentList.size();
        }

        public void addFragment(Fragment fragment, String title) {
            mFragmentList.add(fragment);
            mFragmentTitleList.add(title);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return mFragmentTitleList.get(position);
        }
    }
}

And Yout layout should be like this :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:layout_marginBottom="20dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is button"
        android:textSize="18sp" />

    <TextView
        android:layout_marginBottom="20dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#ff000000"
        android:textSize="18sp"
        android:text="This fragment is not scrollable. How to make toolbar visible?"/>

    <LinearLayout
        android:id="@+id/period_tablayout_linear_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <android.support.design.widget.TabLayout
            android:id="@+id/period_tab_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            app:tabPaddingStart="0dp"
            app:tabPaddingEnd="0dp"
            app:tabIndicatorHeight="2dp"
            app:tabMode="fixed"
            app:tabGravity="fill">

        </android.support.design.widget.TabLayout>

        <android.support.v4.view.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"  />

    </LinearLayout>

</LinearLayout>
Darshan Joshi
  • 111
  • 1
  • 10