menu_on_top
menu_on_top

Reputation: 2613

Horizontal scroll view in horizontal scroll pages

I have an app based on Android-ViewPagerIndicator.

I would like to create an HorizontalScrollView in a Fragment .The view will include some pictures. My problem is that my Scrolling view isn't working beacuse when I'm trying to scroll, I scroll all the fragment and not only the view I want. Hope my question is understandable! :)

This is a part of code:

.xml

   <HorizontalScrollView android:id="@+id/horizontalScroll"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" 
    android:scrollbars="none" 
    android:fadingEdgeLength="10dp">
<LinearLayout 
        android:id="@+id/harokLayout"
        android:background="#EEEEEE"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <ImageView android:src="@drawable/app2" android:layout_height="wrap_content" android:layout_width="wrap_content" />
        <ImageView android:src="@drawable/app1" android:layout_height="wrap_content" android:layout_width="wrap_content" />
        <ImageView android:src="@drawable/app2" android:layout_height="wrap_content" android:layout_width="wrap_content" />
        <ImageView android:src="@drawable/app1" android:layout_height="wrap_content" android:layout_width="wrap_content" />
        <ImageView android:src="@drawable/app2" android:layout_height="wrap_content" android:layout_width="wrap_content" />
        <ImageView android:src="@drawable/app1" android:layout_height="wrap_content" android:layout_width="wrap_content" />
        <ImageView android:src="@drawable/app2" android:layout_height="wrap_content" android:layout_width="wrap_content" />
        <ImageView android:src="@drawable/app1" android:layout_height="wrap_content" android:layout_width="wrap_content" />
        <ImageView android:src="@drawable/app2" android:layout_height="wrap_content" android:layout_width="wrap_content" />
        <ImageView android:src="@drawable/app1" android:layout_height="wrap_content" android:layout_width="wrap_content" />
        <ImageView android:src="@drawable/app2" android:layout_height="wrap_content" android:layout_width="wrap_content" />
        <ImageView android:src="@drawable/app1" android:layout_height="wrap_content" android:layout_width="wrap_content" />

    </LinearLayout>

</HorizontalScrollView>

TabPageIndicator:

import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.TextView;

/**
 * This widget implements the dynamic action bar tab behavior that can change
 * across different configurations or circumstances.
 */
public class TabPageIndicator extends HorizontalScrollView implements PageIndicator {
    Runnable mTabSelector;

    private OnClickListener mTabClickListener = new OnClickListener() {
        public void onClick(View view) {
            TabView tabView = (TabView)view;
            mViewPager.setCurrentItem(tabView.getIndex());
        }
    };

    private LinearLayout mTabLayout;
    private ViewPager mViewPager;
    private ViewPager.OnPageChangeListener mListener;

    private LayoutInflater mInflater;

    int mMaxTabWidth;
    private int mSelectedTabIndex;

    public TabPageIndicator(Context context) {
        this(context, null);
    }

    public TabPageIndicator(Context context, AttributeSet attrs) {
        super(context, attrs);
        setHorizontalScrollBarEnabled(false);

        mInflater = LayoutInflater.from(context);

        mTabLayout = new LinearLayout(getContext());
        addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.FILL_PARENT));
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final boolean lockedExpanded = widthMode == MeasureSpec.EXACTLY;
        setFillViewport(lockedExpanded);

        final int childCount = mTabLayout.getChildCount();
        if (childCount > 1 && (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) {
            if (childCount > 2) {
                mMaxTabWidth = (int)(MeasureSpec.getSize(widthMeasureSpec) ); //edw itan * 0.4f
            } else {
                mMaxTabWidth = MeasureSpec.getSize(widthMeasureSpec) / 2;
            }
        } else {
            mMaxTabWidth = -1;
        }

        final int oldWidth = getMeasuredWidth();
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        final int newWidth = getMeasuredWidth();

        if (lockedExpanded && oldWidth != newWidth) {
            // Recenter the tab display if we're at a new (scrollable) size.
            setCurrentItem(mSelectedTabIndex);
        }
    }

    private void animateToTab(final int position) {
        final View tabView = mTabLayout.getChildAt(position);
        if (mTabSelector != null) {
            removeCallbacks(mTabSelector);
        }
        mTabSelector = new Runnable() {
            public void run() {
                final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2;
                smoothScrollTo(scrollPos, 0);
                mTabSelector = null;
            }
        };
        post(mTabSelector);
    }

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mTabSelector != null) {
            // Re-post the selector we saved
            post(mTabSelector);    
        }
    }

    @Override
    public void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mTabSelector != null) {
            removeCallbacks(mTabSelector);
        }
    }

    private void addTab(String text, int index) {
        //Workaround for not being able to pass a defStyle on pre-3.0
        final TabView tabView = (TabView)mInflater.inflate(R.layout.vpi__tab, null);
        tabView.init(this, text, index);
        tabView.setFocusable(true);
        tabView.setOnClickListener(mTabClickListener);

        mTabLayout.addView(tabView, new LinearLayout.LayoutParams(0, LayoutParams.FILL_PARENT, 1));
    }

    @Override
    public void onPageScrollStateChanged(int arg0) {
        if (mListener != null) {
            mListener.onPageScrollStateChanged(arg0);
        }
    }

    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {
        if (mListener != null) {
            mListener.onPageScrolled(arg0, arg1, arg2);
        }
    }

    @Override
    public void onPageSelected(int arg0) {
        setCurrentItem(arg0);  
        if (mListener != null) {
            mListener.onPageSelected(arg0);
        }
    }

    @Override
    public void setViewPager(ViewPager view) {
        final PagerAdapter adapter = view.getAdapter();
        if (adapter == null) {
            throw new IllegalStateException("ViewPager does not have adapter instance.");
        }
        if (!(adapter instanceof TitleProvider)) {
            throw new IllegalStateException("ViewPager adapter must implement TitleProvider to be used with TitlePageIndicator.");
        }
        mViewPager = view;
        view.setOnPageChangeListener(this);
        notifyDataSetChanged();
    }

    public void notifyDataSetChanged() {
        mTabLayout.removeAllViews();
        TitleProvider adapter = (TitleProvider)mViewPager.getAdapter();
        final int count = ((PagerAdapter)adapter).getCount();
        for (int i = 0; i < count; i++) {
            addTab(adapter.getTitle(i), i);
        }
        if (mSelectedTabIndex > count) {
            mSelectedTabIndex = count - 1;
        }
        setCurrentItem(mSelectedTabIndex);
        requestLayout();
    }

    @Override
    public void setViewPager(ViewPager view, int initialPosition) {
        setViewPager(view);
        setCurrentItem(initialPosition);
    }

    @Override
    public void setCurrentItem(int item) {
        if (mViewPager == null) {
            throw new IllegalStateException("ViewPager has not been bound.");
        }
        mSelectedTabIndex = item;
        final int tabCount = mTabLayout.getChildCount();
        for (int i = 0; i < tabCount; i++) {
            final View child = mTabLayout.getChildAt(i);
            final boolean isSelected = (i == item);
            child.setSelected(isSelected);
            if (isSelected) {
                animateToTab(item);
            }
        }
    }

    @Override
    public void setOnPageChangeListener(OnPageChangeListener listener) {
        mListener = listener;
    }

    public static class TabView extends LinearLayout {
        private TabPageIndicator mParent;
        private int mIndex;

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

        public void init(TabPageIndicator parent, String text, int index) {
            mParent = parent;
            mIndex = index;

            TextView textView = (TextView)findViewById(android.R.id.text1);
            textView.setText(text);
        }

        @Override
        public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);

            // Re-measure if we went beyond our maximum size.
            if (mParent.mMaxTabWidth > 0 && getMeasuredWidth() > mParent.mMaxTabWidth) {
                super.onMeasure(MeasureSpec.makeMeasureSpec(mParent.mMaxTabWidth, MeasureSpec.EXACTLY),
                        heightMeasureSpec);
            }
        }

        public int getIndex() {
            return mIndex;
        }
    }
}

FragmentPagerAdapter2:

import java.util.List;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

 class FragmentPagerAdapter2 extends FragmentPagerAdapter implements TitleProvider {

    private final List<Fragment> fragments;

    /**
     * @param fm
     * @param fragments
     */
    public FragmentPagerAdapter2(FragmentManager fm, List<Fragment> fragments) {
        super(fm);
        this.fragments = fragments;
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.support.v4.app.FragmentPagerAdapter#getItem(int)
     */
    @Override
    public Fragment getItem(int position) {
        return this.fragments.get(position);
    }

    /*
     * (non-Javadoc)
     * 
     * @see android.support.v4.view.PagerAdapter#getCount()
     */
    @Override
    public int getCount() {
        return this.fragments.size();
    }

    public String getTitle(int position) {
        return MarketAppActivity.CONTENT[position % MarketAppActivity.CONTENT.length].toUpperCase();
    }
}

Upvotes: 5

Views: 5994

Answers (2)

Jade Byfield
Jade Byfield

Reputation: 4816

Have you considered using a ViewPager inside your fragment? It seems to be what you're going for as far as the horizontal scrolling/swiping goes, but it's alot less leg work. You basically provide a list of fragments/fragment layouts to your viewpager in your activity, and set your PageAdapter like you normally would. You can either reuse layouts, or create different layouts for each page in your pager. You can check out this blog post for a little more clarity.

http://thepseudocoder.wordpress.com/2011/10/05/android-page-swiping-using-viewpager/

Upvotes: 0

OldSchool4664
OldSchool4664

Reputation: 1472

You must create a custom child class of HorizontalScrollView and modify onTouchEvent to intercept the touch event from the fragment if a horizontal swipe is detected.

For example:

public class CustomHorizontalScrollView extends HorizontalScrollView {

    ...

    public void setParent(ViewPager parentView) {
        mParentView = parentView;
    }

    @Override
    public synchronized boolean onTouchEvent(MotionEvent event) {
        if ((event.getAction() == MotionEvent.ACTION_DOWN) &&
            (mParentView != null)) {
            mParentView.requestDisallowInterceptTouchEvent(true);
        }

        return super.onTouchEvent(event);
    }

    ...

}

mParentView is of course a reference to the ViewPager the fragments are attached to. This way, all further actions associated with that particular MotionEvent (ACTION_MOVE and ACTION_UP) will be given to the child HorizontalScrollView, bypassing the ViewPager altogether.

Upvotes: 1

Related Questions