Solution-1: By specifying a very large number as the actual count, but maps them to the actual range of the dataset/pageset
ViewPager as a circular queue / wrapping
Problem: It doesn't work if there are less than 4 items.
Solution-2 Adding 2 extra items i.e. last item in the first and first item in the last and onPageSelected, depending on the position values, set the current item
Implementing Circular Scrolling In PagerAdapter
Problem: Extra pager indicators and extra fragment instances.
Solution-3: Using the onTouchListener on ViewPager
Implementing Circular Scrolling In PagerAdapter
Problem: The first MotionEvent is always null. Is it because of the ViewPager's own onTouchListener implementation?
Is there a proper solution for this?
Or even if the 3rd solution works fine, it would be great.
I use a combination of Solution 2 and Solution 3, I use the on touch listener of the pager to watch for swipes and see if I need to show the copy of the first or last page based on the current page
example:
mPager.setOnTouchListener(new OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
dxInitial=event.getX();
//
}else if(event.getAction() == MotionEvent.ACTION_MOVE){
//
if(event.getX() - dxInitial > 50 && currentPage==1){
}else if(dxInitial - event.getX() > 50 && currentPage==5){
mPager.setCurrentItem(0,false);
}else if(dxInitial - event.getX() > 50 && currentPage==6){
mPager.setCurrentItem(1,false);
}else if(event.getX() - dxInitial > 50 && currentPage==0){
mPager.setCurrentItem(5,false);
}else if(event.getX() - dxInitial > 100 && currentPage==6){
//
mPager.setCurrentItem(1,false);
}
}
return false;
}
});
you have extra pager indicators but the user should never see or notice them, just set smoothScroll to false when you change the page
Related
i'm using viewpagerIndicator in my app, i have 200 pages. is possible disable the Swipe 1 page before the last page?
Example my currentpage is the 199 here the swipe is disble and never change to the next page, only the previous pages.
EDIT: i have one calendar in the Tabindicator, the pages show info for day, i need show the next day but not swipe because not exist info for this reason i need disable this page.
Exam:
19/ago/2014 | 20/ago/2014 | 21/ago/2014
before |Current |Last Page
in before i can swipe left and right but in Current i need only swipe left and disable right is possible?
You can return 199 from getCount() from adapter that way viewpager will not know there are 200 pages.
EDIT:
Well In that case, you have to override viewpager and manually disable the motion when viewpager is showing second last page.
It would look something like this
First extend : class CustomViewPager extends ViewPager {...}
float lastX;
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if(getCurrentItem() == getAdapter().getCount()-1){
if(ev.getAction() == MotionEvent.ACTION_DOWN){
lastX = ev.getX();
// Just touch down let viewpager also handle touch event
return super.onInterceptTouchEvent(event);
}
else if(ev.getAction() == MotionEvent.ACTION_MOVE){
float xDiff = ev.getX() - lastX;
if(xDiff > 0){
// Attempt to move right on second last page
// Return false, we dont want to handle this movement
return false;
}
else{
// Left you can move
return super.onInterceptTouchEvent(event);
}
}
// Notice that we are not updating lastX on motion towards left
// This is to enable user can swipe towards left a bit and comeback, but dont dare go right
}
else{
// Not on second last page let viewpager handle page event
return super.onInterceptTouchEvent(event);
}
}
I have an achartengine GraphicalView chart inside a android.support.v4.view.ViewPager.
I want my chart to pan when the user drags her finger on it, but now the event is being caught by the ViewPager after a small drag movement.
Preferably, I would like to be able to let the user pan to the end of the chart and then let the ViewPager switch pages.
As an alternative, I would like to at least stop the ViewPager from catching the drag movement inside the chart.
Any ideas?
Here goes my solution.
It allows the user to drag the graph around while there is data in it. After that, the drag events are caught by the ViewPager.
Like I said, the key is this solution is the requestDisallowInterceptTouchEvent function.
public class ParameterGraphicalView extends org.achartengine.GraphicalView {
// stores the data model size
private int mDataSize = 0;
// stores the first X position in the dataset
private long mDataStartX = 0;
// stores the last X position in the dataset
private long mDataEndX = 0;
// the ViewPager
private ViewParent mViewPager;
//(...)
#Override
public boolean onTouchEvent(MotionEvent event) {
// save the position of the first touch so we can determine whether the user is dragging
// left or right
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mFirstTouchX = event.getX();
}
// when mViewPager.requestDisallowInterceptTouchEvent(true), the viewpager does not
// intercept the events, and the drag events (pan, pinch) are caught by the GraphicalView
// we want to keep the ViewPager from intercepting the event if:
// 1- there are 2 or more touches, i.e. the pinch gesture
// 2- the user is dragging to the left but there is no data to show to the right
// 3- the user is dragging to the right but there is no data to show to the left
if (event.getPointerCount() > 1
|| (event.getX() < mFirstTouchX && mDataSize > 0 && mRenderer.getXAxisMax() < mDataEndX)
|| (event.getX() > mFirstTouchX && mData.size() > 0 && mRenderer.getXAxisMin() > mDataStartX)) {
mViewPager.requestDisallowInterceptTouchEvent(true);
}
else {
mViewPager.requestDisallowInterceptTouchEvent(false);
}
return super.onTouchEvent(event);
}
}
I think you should Implement your own ViewPager and handle Touch event yourself.
Maybe this Link helps you : how to disable viewpager adapter on touching specific views?
I've implemented a ViewPager, which serves ImageViews, as demonstrated in this article and source:
http://android-developers.blogspot.com/2011/08/horizontal-view-swiping-with-viewpager.html
http://code.google.com/p/viewpagerexample/source/browse/trunk/AwesomePager/src/com/geekyouup/paug/awesomepager/AwesomePagerActivity.java
Rendering is fine, but I get a very strange gesture problem when trying to swipe through the content of the pager. It seems like the left-right swipe gestures don't get captured correctly, so the pager just snaps back to the 0th element. If I keep playing with the gestures, maybe 1 out of 50 times I can get it to advance to the next page.
I'm using this in a ListView (via getListView().addHeaderView(myViewPager)). Other than that, everything is the same. Has anyone else had success with this implementation?
Thanks
if you use viewpager as listview's header ,you need to do this then the viewpager can works fine.
viewPager.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
PointF downP = new PointF();
PointF curP = new PointF();
int act = event.getAction();
if(act == MotionEvent.ACTION_DOWN || act == MotionEvent.ACTION_MOVE || act == MotionEvent.ACTION_UP){
((ViewGroup) v).requestDisallowInterceptTouchEvent(true);
if (downP.x == curP.x && downP.y == curP.y) {
return false;
}
}
return false;
}
I have spent a ridiculous number of hours trying to get a functioning, responsive mapview fragment working in my viewpager, and now that it is finally working I'm not quite sure why!
Background:
I am using ActionBarSherlock for my actionbar, I am using a viewpager to switch between three fragments: a list, an imageview + textview, and a mapview. I have a viewpagerindicator to go with my viewpager. I am using the maps version of the android-support-v4.
What Worked:
- Override the viewpager's onInterceptTouchEvent method to return false
- Set an onClickListener on the mapview that does nothing.
The mapview would appear, but would not respond before I added the listener, but why did adding an onclicklistener make ALL the gestures responsive?
Maybe you should start again. In my case, all i had to do was put MapFragment in ViewPager with FragmentPageAdapter.
Then created my own ViewPager with overriden method just to make MapFragment usable:
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// hacky hack to never intercept map pages events unless its on the
// very edge of screen - last or first fifth of the view size
if (((FragmentPagerAdapter) getAdapter()).getItem(getCurrentItem()) instanceof SupportMapFragment) {
if (event.getAction() == MotionEvent.ACTION_DOWN && event.getX() < (getWidth() - (getWidth() / 5)) && event.getX() > (getWidth() / 5)) {
// Never allow swiping to switch if not right on the edge
return false;
}
}
return super.onInterceptTouchEvent(event);
}
I have a ViewPager on the root-level of an activity.
Each page of the pager contains a ListFragment (backed by a FragmentPagerAdapter).
Some of the list view items should contain additionally ViewPagers to support swiping the content of those items (e. g. a horizontal gallery inside a list item).
How can I nest view pagers? ViewPager -> ListView (in a page) -> ViewPager (inside a list item)
I can swipe between the ListFragments horizontally and I can swipe the whole list vertically, but I cannot swipe inside list items.
I added an OnTouchListener to the interior ViewPager:
private OnTouchListener mSuppressInterceptListener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(
event.getAction() == MotionEvent.ACTION_DOWN &&
v instanceof ViewGroup
) {
((ViewGroup) v).requestDisallowInterceptTouchEvent(true);
}
return false;
}
};
This just detects ACTION_DOWN touch events on the inner ViewPager and prevents the outer one from intercepting it. Because it returns false, only the ACTION_DOWN event should be hit; all the other events will be ignored. You can add this listener to every element you want to "protect" from the outer ViewPager's scrolling, though obviously if you want to pick up any other touch behaviour on those elements you'll need to deal with them inside the touch listener and possibly implement a better listener.
Credit to #Rodja who gave me the idea in the first place.
While it's not the best interaction design, it is possible to implement this by overwriting the dispatchTouchEvent(MotionEvent ev) method of the root-level Activity and using requestDisallowInterceptTouchEvent(true) on the mainPager and the current ListView to prevent other scrolling. Look at this example:
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Fragment listFragment = getSupportFragmentManager().findFragmentByTag(
"android:switcher:" + R.id.pager + ":" + (mainPager.getCurrentItem()));
mainPager.getChildAt(mainPager.getCurrentItem());
if (listFragment == null)
return super.dispatchTouchEvent(ev);
ViewPager embeddedPager = (ViewPager) listFragment.getView().findViewById(R.id.videopager);
if (embeddedPager != null) {
int[] position = new int[2];
embeddedPager.getLocationOnScreen(position);
if (ev.getY() > position[1] && ev.getY() < position[1] + embeddedPager.getHeight()) {
mainPager.requestDisallowInterceptTouchEvent(true);
if (embeddedPager.getScrollX() % embeddedPager.getWidth() != 0) {
ListView listView = (ListView) listFragment.getView().findViewById(
android.R.id.list);
listView.requestDisallowInterceptTouchEvent(true);
}
}
}
return super.dispatchTouchEvent(ev);
}
You can't really nest elements that need the same gestures to control them. Since the view pager is already capturing the horizontal motion, your nested elements will not get it. You could probably do a lot of work to get around this by managing focus and the like - but in the end your app will be confusing for users. Its really better to not nest elements that would use the same interaction... in this case two view pagers both watching for a side to side motion.