I am able to implement TabLayout with ViewPager nicely but when the content inside the ViewPager is being scrolled (the deceleration animation), I cannot swipe left and right to change to other fragments inside ViewPager. I have to wait until the scrolling animation stops and then swipe.
Below is some of my code snippets.
I have a simple activity_main.xml layout like below.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbarHome"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"/>
<LinearLayout
android:id="#+id/mainContainerLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
</LinearLayout>
<android.support.design.widget.BottomNavigationView
android:id="#+id/btmNavView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white"
app:menu="#menu/menu_main" />
</LinearLayout>
I then inflate a fragment containing TabLayout and ViewPager into the LinearLayout in the middle of the activity_main.xml. This layout can be seen below:
<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">
<com.pchatanan.sontana.custom_views.AppTabLayout
android:id="#+id/contactTabLayout"
app:tabMode="fixed"
android:layout_height="wrap_content"
android:layout_width="match_parent"
style="#style/AppTabLayout"/>
<android.support.v4.view.ViewPager
android:id="#+id/contactViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
The logic inside my fragment is below:
fragmentArray = new Fragment[]{new SimpleFragment(), new SimpleFragment(), new SimpleFragment()};
titleArray = new String[]{"fragment1", "fragment2", "fragment3"};
contactPagerAdapter = new AppPagerAdapter(getChildFragmentManager(), fragmentArray, titleArray);
contactViewPager.setAdapter(contactPagerAdapter);
contactViewPager.setOffscreenPageLimit(fragmentArray.length - 1);
contactTabLayout.setupWithViewPager(contactViewPager);
Use this instead defualt ViewPager.
Detect when ScrollView or RecyclerView is scrolling. Then call
viewPager.setPagingEnabled(pagingEnable);
If pagingEnable
public class CustomViewPager extends ViewPager {
private boolean isPagingEnabled = true;
public CustomViewPager(Context context) {
super(context);
}
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean onTouchEvent(MotionEvent event) {
return this.isPagingEnabled && super.onTouchEvent(event);
}
public boolean onInterceptTouchEvent(MotionEvent event) {
return this.isPagingEnabled && super.onInterceptTouchEvent(event);
}
public void setPagingEnabled(boolean b) {
this.isPagingEnabled = b;
}
}
Update:
You can do reverse to like you can disable ScrollView scroll when ViewPager is swiping
mScrollView.requestDisallowInterceptTouchEvent(true);
Similar to what suggested by #Khemraj, the problem is the touch is not intercepted by ViewPager. It is only intercepted by the ScrollView. To fix this, we should allow ViewPage to intercept the touch when scrolling:
scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
#Override
public void onScrollChange(View view, int i, int i1, int i2, int i3) {
viewPager.requestDisallowInterceptTouchEvent(false);
}
});
A better implementation is to make use of CallBackListener onto the fragment containing the scrollView.
Related
I have a created a custom viewpager, and i would like the user to swipe and change pages only from a part of the screen.
Every page has a linearlayout at the bottom with some text, and i would like to swipe only from there, not from the hole screen.
Is that possible?
This is my custom viewpager class:
public class MyViewPager extends ViewPager {
private boolean mSwipable = true;
public MyViewPager(Context context) {
super(context);
}
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return mSwipable ? super.onInterceptTouchEvent(event) : false;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return mSwipable ? super.onTouchEvent(event) : false;
}
public boolean isSwipable() {
return mSwipable;
}
public void setSwipable(boolean swipable) {
mSwipable = swipable;
}
}
and this is the view of a page:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:clipChildren="false"
android:clipToPadding="false"
android:fillViewport="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/fragment_search">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/bottomLayout"
android:layout_marginBottom="#dimen/bottom_bar_height">
//show some stuff here
</LinearLayout>
<LinearLayout
android:id="#+id/bottomMenu"
android:layout_width="match_parent"
android:layout_height="#dimen/bottom_bar_height"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom"
android:orientation="horizontal">
// this is my footer, where i need to change the pages by swipe
</LinearLayout>
</RelativeLayout>
Follow this question in order to be able to disable swiping at will How do disable paging by swiping with finger in ViewPager but still be able to swipe programmatically?
And combine that with your SliderAdapter in order to control which pages will be swipeable or not.
If you followed the link above, on your subclass of ViewPager, you can add some GestureDetector on onTouchEvent(MotionEvent event) and feed it with your event, like Android: How to handle right to left swipe gestures
By doing this, you will now have some onSwipeRight and manage there your logic, delegating to the adapter the question if the page should be swiped or not, or where to go next.
I am currently experimenting with CoordinatorLayout + AppbarLayout + CollapsingToolbarLayout in a way such that:
1) Scroll down the Appbar using "Toolbar" [ No Nested ScrollView / RecyclerView ].
2) The content below the appbar should move along with the appbar scrolling.
3) Multiple images kept under ViewPager.
4) The last item in the ViewPager would be an textview.
I have achieved 1) and 2) using the following layout :
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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"
xmlns:tools="http://schemas.android.com/tools">
<android.support.design.widget.AppBarLayout
android:id="#+id/flexible.example.appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
>
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/flexible.example.collapsing"
android:layout_width="match_parent"
android:layout_height="300dp"
app:expandedTitleMarginBottom="94dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:contentScrim="?colorPrimary"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:id="#+id/text_sample"
android:scrollbars="vertical"
android:scrollIndicators="right"
app:layout_collapseMode="parallax"
app:layout_scrollFlags="scroll|enterAlways"
android:layout_gravity="center"
android:nestedScrollingEnabled="true"
/>
</android.support.design.widget.CollapsingToolbarLayout>
<android.support.v7.widget.Toolbar
android:id="#+id/ioexample.toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/PM01"
android:elevation="4dp"
app:layout_collapseMode="pin"
app:layout_anchor="#id/flexible.example.collapsing"
app:layout_anchorGravity="bottom"
app:theme="#style/ThemeOverlay.AppCompat.Light"
style="#style/ToolBarWithNavigationBack"
app:layout_scrollFlags="scroll|enterAlways|snap"
>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/recyclerviewcontainer"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
What I am trying to achieve now is to make the textview inside collpasingtoolbarlayout is to be scrollable (#4 above). Since my search till now has made me believe that the Appbar is handling all the touch events by itself, this doesn't seems to be easy. But since it is a requirement, I would be more than happy to have a guidance / pointers to help me complete this.
Can someone please let me know what and where to look for achieving this functionality.
After a lot of research and some more searching through SO, I got an idea what I need to do in order to achieve the desired effect:
1) Implement a custom behavior for appbarlayout :
public class AppBarLayoutCustomBehavior extends AppBarLayout.Behavior {
private boolean setIntercept = false;
private boolean lockAppBar = false;
DragCallback mDragCallback = new DragCallback() {
#Override
public boolean canDrag(#NonNull AppBarLayout appBarLayout) {
return !lockAppBar;
}
};
#Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
super.onInterceptTouchEvent(parent, child, ev);
return setIntercept;
}
public void setInterceptTouchEvent(boolean set) {
setIntercept = set;
}
public AppBarLayoutCustomBehavior() {
super();
setDragCallback(mDragCallback);
}
public AppBarLayoutCustomBehavior(Context ctx, AttributeSet attributeSet) {
super(ctx, attributeSet);
setDragCallback(mDragCallback);
}
public void lockAppBar() {
lockAppBar = true;
}
public void unlockAppBar() {
lockAppBar = false;
}
}
2) Use this custom behavior with app bar :
CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)appBarLayout.getLayoutParams();
final AppBarLayoutCustomBehavior mBehavior = new AppBarLayoutCustomBehavior();
lp.setBehavior(mBehavior);
/// use toolbar to enable/disable dragging on the appbar behavior. This way
/// out toolbar acts as a drag handle for the app bar.
Toolbar toolbar = (Toolbar) activity.findViewById(R.id.main_toolbar);
toolbar.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
mBehavior.setInterceptTouchEvent(true);
return true;
case MotionEvent.ACTION_CANCEL:
mBehavior.setInterceptTouchEvent(false);
return true;
}
return false;
}
});
3) Set movement method on the textview to make it scrollable
textView.setMovementMethod(ScrollingMovementMethod.getInstance());
I have a layout with custom ScrollView that can be switched off. There are some fragments loading into this ScrollView.
Today I added RecycleView to the new fragment and noticed a strange behaviour. When RecycleView has android:height="match_parent" it expands to full its height inside ScrollView.
Is there any way to disable this (I want RecycleView to scroll internally and to be screen_height size) ?
Main content xml (located inside CoordinatorLayout)
<xxx.SwitchableScrollView
android:id="#+id/main_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:id="#+id/fragment_holder"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="ScrollViewSize"/>
</xxx.SwitchableScrollView>
Fragment layout:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/appeals_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="visible"/>
<LinearLayout
android:id="#+id/loading_progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ProgressBar
android:layout_width="#dimen/big_progress_diameter"
android:layout_height="#dimen/big_progress_diameter"
android:indeterminate="true"
android:indeterminateDrawable="#drawable/custom_progress_bar_primary"/>
</LinearLayout>
</FrameLayout>
Extended ScrollView:
public class SwitchableScrollView extends ScrollView {
boolean allowScroll = true;
public boolean isAllowScroll() {
return allowScroll;
}
public void setAllowScroll(boolean allowScroll) {
this.allowScroll = allowScroll;
}
// .... constructors skipped
#Override
public boolean onTouchEvent(MotionEvent ev) {
return allowScroll && super.onTouchEvent(ev);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return allowScroll && super.onInterceptTouchEvent(ev);
}
}
RecycleView init:
listView = (NestedRecyclerView) v.findViewById(R.id.appeals_list);
listView.setHorizontalScrollBarEnabled(false);
listView.setVerticalScrollBarEnabled(true);
listView.setNestedScrollingEnabled(true);
adapter = new AppealListAdapter(appealList);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
listView.setLayoutManager(layoutManager);
listView.setAdapter(adapter);
new GetAppeals().execute();
I'm using support library 23.2.1 (also tried 23.2.0). ListView and GridView works good in another fragments.
Finally I found an answer. I spent 6 hours(!) to add this one line to code:
layoutManager.setAutoMeasureEnabled(false);
They should be crazy to enable such thing by default...
I'm trying to get a fullscreen CollapsingToolbar but when I set match_parent to the height of AppBarLayout I'm not able to scroll the ImageView which is inside CollapsingToolbarLayout. I have to leave some space so that I can touch the "white" of the activity (in AppBarLayout I added android:layout-marginBottom:"16dp" ) and only then, after I touched it, I can scroll the ImageView otherwise I can't.
This happens everytime I run the app and touch the layout for the first time. So I have to touch the white first and then scroll the image.
Could you help me?
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#+id/drawer">
<android.support.design.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="16dp"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="#+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleMarginStart="48dp"
app:expandedTitleMarginEnd="64dp">
<ImageView
android:id="#+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:fitsSystemWindows="true"
app:layout_collapseMode="parallax"
android:contentDescription="#null"
android:src="#drawable/background" />
<android.support.v7.widget.Toolbar
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:layout_collapseMode="pin"
app:theme="#style/ToolbarTheme"
android:id="#+id/toolbar"/>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="#+id/scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
</FrameLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
<com.myapplication.ScrimInsetsFrameLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="304dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:insetForeground="#4000"
android:clickable="true"
android:background="#ffffff">
...
</com.myapplication.ScrimInsetsFrameLayout>
</android.support.v4.widget.DrawerLayout>
EDIT #PPartisan I've done what you said but here's what I got:
This isn't a nice solution, but it does work on my test device. It kick starts the scrolling process by explicitly assigning a touch listener to the AppBar that triggers a nested scroll.
First, create a custom class that extends NestedScrollView and add the following method so it look something like this:
public class CustomNestedScrollView extends NestedScrollView {
private int y;
public CustomNestedScrollView(Context context) {
super(context);
}
public CustomNestedScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean dispatchHandlerScroll(MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
y = (int) e.getY();
startNestedScroll(2);
break;
case MotionEvent.ACTION_MOVE:
int dY = y - ((int)e.getY());
dispatchNestedPreScroll(0, dY, null, null);
dispatchNestedScroll(0, 0, 0, dY, null);
break;
case MotionEvent.ACTION_UP:
stopNestedScroll();
break;
}
return true;
}
}
Then, inside your Activity class, assign a TouchListener to your AppBarLayout:
appBarLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return customNestedScrollView.dispatchHandlerScroll(event);
}
});
and remove it when the AppBar collapses fully for the first time:
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (Math.abs(appBarLayout.getY()) == appBarLayout.getTotalScrollRange()) {
appBarLayout.setOnTouchListener(null);
}
return super.dispatchTouchEvent(ev);
}
Edit
Take the following steps to get it up and running:
Replace the NestedScrollView in your xml(android.support.v4.widget.NestedScrollView) with the CustomNestedScrollView (which will take the form of com.something.somethingelse.CustomNestedScrollView, depending on where it is in your project).
Assign it to a variable in your Activity onCreate()(i.e. CustomScrollView customScrollView = (CustomScrollView) findViewById(R.id.custom_scroll_view_id);)
Set up the TouchListener on your appBarLayout as you have done in your edit. Now when you call dispatchHandlerScroll(), it will be on your customNestedScrollView instance.
dispatchTouchEvent() is a method you override in your Activity class, so it should be outside the TouchListener
So, for example:
public class MainActivity extends AppCompatActivity {
private AppBarLayout appBarLayout;
private CustomNestedScrollView customNestedScrollView;
//...
#Override
protected void onCreate(Bundle savedInstanceState) {
//...
customNestedScrollView = (CustomNestedScrollView) findViewById(R.id.scroll);
appBarLayout = (AppBarLayout) findViewById(R.id.app_bar_layout);
appBarLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return customNestedScrollView.dispatchHandlerScroll(event);
}
});
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (Math.abs(appBarLayout.getY()) == appBarLayout.getTotalScrollRange()) {
appBarLayout.setOnTouchListener(null);
}
return super.dispatchTouchEvent(ev);
}
}
Hope that's cleared things up.
Try to add a tiny margin so the white space below will be almost invisible (you might also want to change white to accent color so the space will not be visible)
Another approach is to set the height of app bar layout dynamically by getting the height of the screen.
EDIT:
This might be a focus problem, try to add dummy layout to your main content, that will be focused automatically
<LinearLayout
android:layout_width="0px"
android:layout_height="0px"
android:focusable="true"
android:focusableInTouchMode="true" />
or even just add these attributes to your content layout
android:focusable="true"
android:focusableInTouchMode="true"
I need to design a ViewPager which able to pass childs with fixed width (e.g childs with 700dp width), Unfortunately the current version of ViewPager will automatically makes all childrens width to MATCH_PARENT, is there any way to add this functionality to ViewPager?
My ViewPager layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
android:id="#+id/some_id"
android:layout_width="match_parent"
android:layout_height="300dp"
android:overScrollMode="never" />
</LinearLayout>
ViewPager childs layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/banner_main_layout_container"
android:layout_width="700dp"
android:layout_height="match_parent"
android:background="#fff"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="some images"/>
</LinearLayout>
Thanks in Advance...
It is possible to scale the pages within the ViewPager with FragmentPagerAdapter.getPageWidth. You will need a custom FragmentPagerAdapter. If you return a number between 0 and 1, the pages are scaled down, width > 1 scales pages up accordingly. But this is not really good, because you can't scroll the image within the up-scaled page.
If you wrap the ImageView in a HorizontalScrollView, things are a bit better, you can scroll the images within pages, but the swipe gesture between pages is caught by the HorizontalScrollView if you are not very fast. See this video.
So the solution is truly to use a custom HorizontalScrollView (see InterceptingHorizontalScrollView) which disallows intercepting the onTouch event, but also allows it when the User scrolls to the end (See overidden onOverScrolled). See this video or the image below for the difference.
EDIT You don't need to override onInterceptTouchEvent, because HorizontalScrollView intercepts them by default (so scrolling the image has higher priority than paging.)
Finally, here's all the code:
MainActivity.java
public class MainActivity extends Activity {
private ViewPager mViewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set up the ViewPager
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setPageMargin(30);
mViewPager.setAdapter(new ImagePagerAdapter(getFragmentManager()));
}
private class ImagePagerAdapter extends FragmentPagerAdapter {
public ImagePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int i) {
switch(i) {
case 0:
return ImageFragment.newInstance(R.drawable.forest1);
case 1:
return ImageFragment.newInstance(R.drawable.forest2);
case 2:
return ImageFragment.newInstance(R.drawable.forest3);
default:
return ImageFragment.newInstance(R.drawable.ic_launcher);
}
}
#Override
public int getCount() {
return 3;
}
#Override
public float getPageWidth(int position)
{
// Here it is possible to scale page width
return super.getPageWidth(position);
}
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
ImageFragment.java
public class ImageFragment extends Fragment {
private static final String ARG_PARAM1 = "image_resid";
private int mImageResId;
public static ImageFragment newInstance(int image_resid) {
ImageFragment fragment = new ImageFragment();
Bundle args = new Bundle();
args.putInt(ARG_PARAM1, image_resid);
fragment.setArguments(args);
return fragment;
}
public ImageFragment() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mImageResId = getArguments().getInt(ARG_PARAM1);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_image, container, false);
ImageView imageView = (ImageView)v.findViewById(R.id.imageView);
imageView.setImageResource(mImageResId);
return v;
}
}
fragment_image.xml
<com.gyebro.viewpagertest.InterceptingHorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="600dp"
android:layout_height="match_parent"
tools:context="com.gyebro.viewpagertest.ImageFragment">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:id="#+id/imageView"
android:src="#drawable/forest1" />
</com.gyebro.viewpagertest.InterceptingHorizontalScrollView>
InterceptingHorizontalScrollView.java
public class InterceptingHorizontalScrollView extends HorizontalScrollView {
public InterceptingHorizontalScrollView(Context context) {
super(context);
}
public InterceptingHorizontalScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public InterceptingHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/*#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (getParent() != null) {
switch (ev.getAction()) {
case MotionEvent.ACTION_MOVE:
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
getParent().requestDisallowInterceptTouchEvent(false);
break;
}
}
return super.onInterceptTouchEvent(ev);
}*/
#Override
protected void onOverScrolled (int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
super.onOverScrolled(scrollX,scrollY,clampedX,clampedY);
// if clampedX == true, we've reached the end of the HorizontalScrollView so
// allow parent to intercept
if(clampedX) {
Log.d("InterceptingHorizontalScrollView", "Reached the end, allowing interception");
getParent().requestDisallowInterceptTouchEvent(false);
}
}
}
What you really want here is a HorizontalScrollView inside of a ViewPager. This requires custom touch handling, so you'll want to use something like this class: InterceptingHorizontalScrollView
To make InterceptingHorizontalScrollView work in a ViewPager, you'll have to override onOverScrolled:
#Override
protected void onOverScrolled (int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
super.onOverScrolled(scrollX,scrollY,clampedX,clampedY);
if(clampedX) {
getParent().requestDisallowInterceptTouchEvent(false);
}
}
Thanks to Gyebro for this tip.^
Your ViewPager child layout would look like this:
<com.tumblr.widget.InterceptingHorizontalScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="#+id/banner_main_layout_container"
android:layout_width="700dp"
android:layout_height="match_parent"
android:background="#fff"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="some images"/>
</LinearLayout>
</com.tumblr.widget.InterceptingHorizontalScrollView>
You can either override PagerAdapter´s getWidth method and if this does not help, look at this:
http://commonsware.com/blog/2012/08/20/multiple-view-viewpager-options.html
and most importantly try this example, it works great!
Just go along the whole example.
The ViewPager children will/should always match it's parent width.
Furthermore it sounds like a bad idea to use a 700dp width ImageView. What would that look like in portrait mode?
If you don't want to make the ViewPager itself smaller, i.e. you want the ImageViews to be swiped from the absolute side of the screen, you have to make the items appear smaller.
That imitation could be done by creating 2 additional LinearLayouts to act as spacers. Then it would appear as if your item has a specific width.
Here's an example (with a TextView):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout
android:background="#FFF"
android:layout_weight="3"
android:layout_width="0dp"
android:layout_height="match_parent"/>
<TextView
android:layout_weight="10"
android:background="#333"
android:textColor="#FFF"
android:textSize="50sp"
android:gravity="center"
android:text="HELLO"
android:layout_width="0dp"
android:layout_height="match_parent" />
<LinearLayout
android:background="#FFF"
android:layout_weight="3"
android:layout_width="0dp"
android:layout_height="match_parent"/>
</LinearLayout>
And that would look like this:
Set the page margin of the view pager to a negative value. This will force the pages to push into the the view pager. Be warned, it will also cause overlap so you'll see part of the next/previous element in the view pager.