-
-
Save devunwired/8cbe094bb7a783e37ad1 to your computer and use it in GitHub Desktop.
<!-- Copyright (c) 2012 Wireless Designs, LLC | |
Permission is hereby granted, free of charge, to any person obtaining | |
a copy of this software and associated documentation files (the | |
"Software"), to deal in the Software without restriction, including | |
without limitation the rights to use, copy, modify, merge, publish, | |
distribute, sublicense, and/or sell copies of the Software, and to | |
permit persons to whom the Software is furnished to do so, subject to | |
the following conditions: | |
The above copyright notice and this permission notice shall be | |
included in all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
--> | |
<?xml version="1.0" encoding="utf-8"?> | |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent"> | |
<com.example.pagercontainer.PagerContainer | |
android:id="@+id/pager_container" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:background="#CCC"> | |
<android.support.v4.view.ViewPager | |
android:layout_width="150dp" | |
android:layout_height="100dp" | |
android:layout_gravity="center_horizontal" /> | |
</com.example.pagercontainer.PagerContainer> | |
</RelativeLayout> |
/* | |
* Copyright (c) 2012 Wireless Designs, LLC | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining | |
* a copy of this software and associated documentation files (the | |
* "Software"), to deal in the Software without restriction, including | |
* without limitation the rights to use, copy, modify, merge, publish, | |
* distribute, sublicense, and/or sell copies of the Software, and to | |
* permit persons to whom the Software is furnished to do so, subject to | |
* the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be | |
* included in all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
*/ | |
package com.example.pagercontainer; | |
import android.app.Activity; | |
import android.graphics.Color; | |
import android.os.Bundle; | |
import android.support.v4.view.PagerAdapter; | |
import android.support.v4.view.ViewPager; | |
import android.view.Gravity; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.widget.TextView; | |
/** | |
* PagerActivity: A Sample Activity for PagerContainer | |
*/ | |
public class PagerActivity extends Activity { | |
PagerContainer mContainer; | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.main); | |
mContainer = (PagerContainer) findViewById(R.id.pager_container); | |
ViewPager pager = mContainer.getViewPager(); | |
PagerAdapter adapter = new MyPagerAdapter(); | |
pager.setAdapter(adapter); | |
//Necessary or the pager will only have one extra page to show | |
// make this at least however many pages you can see | |
pager.setOffscreenPageLimit(adapter.getCount()); | |
//A little space between pages | |
pager.setPageMargin(15); | |
//If hardware acceleration is enabled, you should also remove | |
// clipping on the pager for its children. | |
pager.setClipChildren(false); | |
} | |
//Nothing special about this adapter, just throwing up colored views for demo | |
private class MyPagerAdapter extends PagerAdapter { | |
@Override | |
public Object instantiateItem(ViewGroup container, int position) { | |
TextView view = new TextView(PagerActivity.this); | |
view.setText("Item "+position); | |
view.setGravity(Gravity.CENTER); | |
view.setBackgroundColor(Color.argb(255, position * 50, position * 10, position * 50)); | |
container.addView(view); | |
return view; | |
} | |
@Override | |
public void destroyItem(ViewGroup container, int position, Object object) { | |
container.removeView((View)object); | |
} | |
@Override | |
public int getCount() { | |
return 5; | |
} | |
@Override | |
public boolean isViewFromObject(View view, Object object) { | |
return (view == object); | |
} | |
} | |
} |
/* | |
* Copyright (c) 2012 Wireless Designs, LLC | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining | |
* a copy of this software and associated documentation files (the | |
* "Software"), to deal in the Software without restriction, including | |
* without limitation the rights to use, copy, modify, merge, publish, | |
* distribute, sublicense, and/or sell copies of the Software, and to | |
* permit persons to whom the Software is furnished to do so, subject to | |
* the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be | |
* included in all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
*/ | |
package com.example.pagercontainer; | |
import android.content.Context; | |
import android.graphics.Point; | |
import android.support.v4.view.ViewPager; | |
import android.util.AttributeSet; | |
import android.view.MotionEvent; | |
import android.widget.FrameLayout; | |
/** | |
* PagerContainer: A layout that displays a ViewPager with its children that are outside | |
* the typical pager bounds. | |
*/ | |
public class PagerContainer extends FrameLayout implements ViewPager.OnPageChangeListener { | |
private ViewPager mPager; | |
boolean mNeedsRedraw = false; | |
public PagerContainer(Context context) { | |
super(context); | |
init(); | |
} | |
public PagerContainer(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
init(); | |
} | |
public PagerContainer(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
init(); | |
} | |
private void init() { | |
//Disable clipping of children so non-selected pages are visible | |
setClipChildren(false); | |
//Child clipping doesn't work with hardware acceleration in Android 3.x/4.x | |
//You need to set this value here if using hardware acceleration in an | |
// application targeted at these releases. | |
setLayerType(View.LAYER_TYPE_SOFTWARE, null); | |
} | |
@Override | |
protected void onFinishInflate() { | |
try { | |
mPager = (ViewPager) getChildAt(0); | |
mPager.setOnPageChangeListener(this); | |
} catch (Exception e) { | |
throw new IllegalStateException("The root child of PagerContainer must be a ViewPager"); | |
} | |
} | |
public ViewPager getViewPager() { | |
return mPager; | |
} | |
private Point mCenter = new Point(); | |
private Point mInitialTouch = new Point(); | |
@Override | |
protected void onSizeChanged(int w, int h, int oldw, int oldh) { | |
mCenter.x = w / 2; | |
mCenter.y = h / 2; | |
} | |
@Override | |
public boolean onTouchEvent(MotionEvent ev) { | |
//We capture any touches not already handled by the ViewPager | |
// to implement scrolling from a touch outside the pager bounds. | |
switch (ev.getAction()) { | |
case MotionEvent.ACTION_DOWN: | |
mInitialTouch.x = (int)ev.getX(); | |
mInitialTouch.y = (int)ev.getY(); | |
default: | |
ev.offsetLocation(mCenter.x - mInitialTouch.x, mCenter.y - mInitialTouch.y); | |
break; | |
} | |
return mPager.dispatchTouchEvent(ev); | |
} | |
@Override | |
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { | |
//Force the container to redraw on scrolling. | |
//Without this the outer pages render initially and then stay static | |
if (mNeedsRedraw) invalidate(); | |
} | |
@Override | |
public void onPageSelected(int position) { } | |
@Override | |
public void onPageScrollStateChanged(int state) { | |
mNeedsRedraw = (state != ViewPager.SCROLL_STATE_IDLE); | |
} | |
} |
Same problem as yarolegovich. Any clue ?
How can I change the text of the selected page?
I added a OnPageChangeListener, but how can I access the textview from my selection, and also the others?
thank you for your code but there is problem in PagerContainer
protected void onFinishInflate() needs Overriding method should call super
can anyone explain this?
Thanks guys for this.
Is there a way to make the next item and the preview item blurred, then when on focus remove the blur ?
thanks
@boshraViva Did you called super.onFinishInflate()? and did you figured out What it does?
Which method is this getNumItemsInScrollableContainer() ?
Guys, I have a problem.
I have 3 items visible.
If I select the 3rd item it will return item on 2nd position.
Do you guys have this problem?
I used two viewpager..in first pager i have only images of product. now if user swipe image from pager 1 then in pager 2 i want to set its different prices..how to do that can any one help?
http://stackoverflow.com/questions/41217237/viewpager-not-getting-last-item
@PrinceRK I am also wondering same. Was checking this code, and surprisingly it is not working for me at all.
@devunwired is there any updates on this code you made. Code seems workable but still it's not working in my scenario. I have ViewPager
inside RecyclerView
. So I have to use wrap_content
for ViewPager
. And have made customization in onMeasure
to get wrapped content. Then I used your piece of code for getting preview of previous and next view. Unfortunately I am not getting it. I don't know what I am missing. I will give CustomViewPager
code over here. In that there is also vertical swipe related code, but that is what I am not using in the discussed scenario. Just wrapping the height. isWrap
is true in below code
/**
* Created by Jimit Patel on 29/07/15.
*/
public class CustomViewPager extends ViewPager {
private static final String TAG = CustomViewPager.class.getSimpleName();
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
public static final int NONE = 0;
public static final int HEIGHT = 1;
public static final int WIDTH = 2;
private boolean isPagingEnabled, isSwipeable, isSquare, isWrap;
private int mSwipeOrientation;
private ScrollerCustomDuration mScroller = null;
private double heightRatio, widthRatio;
private int mCalculationType;
private View mCurrentView;
public CustomViewPager(Context context) {
super(context);
this.isPagingEnabled = true;
this.isSwipeable = true;
isSquare = false;
mCalculationType = NONE;
heightRatio = 0;
widthRatio = 0;
mSwipeOrientation = HORIZONTAL;
postInitViewPager();
}
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
setIsSquare(context, attrs);
setDimensionRatio(context, attrs);
setSwipeOrientation(context, attrs);
this.isPagingEnabled = true;
this.isSwipeable = true;
postInitViewPager();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!this.isPagingEnabled || !this.isSwipeable)
return false;
return super.onTouchEvent(mSwipeOrientation == VERTICAL ? swapXY(event) : event);
}
@Override
public boolean onInterceptHoverEvent(MotionEvent event) {
// return super.onInterceptHoverEvent(event);
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (!this.isPagingEnabled || !this.isSwipeable)
return false;
else if (mSwipeOrientation == VERTICAL) {
boolean intercepted = super.onInterceptHoverEvent(swapXY(event));
swapXY(event);
return intercepted;
}
return super.onInterceptTouchEvent(event);
}
public void setPagingEnabled(boolean isPagingEnabled) {
this.isPagingEnabled = isPagingEnabled;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
boolean isDefault;
int width, height;
switch (mCalculationType) {
case WIDTH: {
isDefault = false;
height = MeasureSpec.getSize(heightMeasureSpec);
width = (int) ((float) (((float) (heightRatio > 0 ? heightRatio : 1) / (float) (widthRatio > 0 ? widthRatio : 1)) * height));
break;
}
case HEIGHT: {
isDefault = false;
width = MeasureSpec.getSize(widthMeasureSpec);
height = (int) ((float) (((float) (widthRatio > 0 ? widthRatio : 1) / (float) (heightRatio > 0 ? heightRatio : 1)) * width));
break;
}
default: {
isDefault = true;
width = widthMeasureSpec;
height = heightMeasureSpec;
break;
}
}
if (!isDefault) {
setMeasuredDimension(width, height);
measureChildren(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), (isSquare
? MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY) : MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)));
} else {
if (!isSquare && isWrap) {
if (mCurrentView == null) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
height = 0;
mCurrentView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = mCurrentView.getMeasuredHeight();
if (h > height) height = h;
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
} else {
super.onMeasure(widthMeasureSpec, isSquare ? widthMeasureSpec : heightMeasureSpec);
}
}
}
public void measureCurrentView(View currentView) {
mCurrentView = currentView;
requestLayout();
}
public void setSwipeOrientation(int swipeOrientation) {
if (swipeOrientation == HORIZONTAL || swipeOrientation == VERTICAL)
mSwipeOrientation = swipeOrientation;
else
throw new IllegalStateException("Swipe Orientation can be either CustomViewPager.HORIZONTAL" +
" or CustomViewPager.VERTICAL");
initSwipeMethods();
}
private void setIsSquare(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SquareViewPager);
boolean isSquare = typedArray.getBoolean(R.styleable.SquareViewPager_square_dimens, false);
setIsSquare(isSquare);
typedArray.recycle();
}
private void setSwipeOrientation(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomViewPager);
mSwipeOrientation = typedArray.getInteger(R.styleable.CustomViewPager_swipe_orientation, 0);
typedArray.recycle();
initSwipeMethods();
}
private void setDimensionRatio(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SquareViewPager);
int ratioWidth = typedArray.getInteger(R.styleable.SquareViewPager_width_ratio, 0);
int ratioHeight = typedArray.getInteger(R.styleable.SquareViewPager_height_ratio, 0);
int calculationType = typedArray.getInteger(R.styleable.SquareViewPager_calculation, 0);
setDimensionRatio(ratioWidth, ratioHeight, calculationType);
typedArray.recycle();
}
private void setDimensionRatio(int ratioWidth, int ratioHeight, int calculationType) {
this.widthRatio = ratioWidth;
this.heightRatio = ratioHeight;
this.mCalculationType = calculationType;
}
public void setIsSquare(boolean isSquare) {
this.isSquare = isSquare;
}
public void setHeightRatio(double heightRatio) {
this.heightRatio = heightRatio;
}
public void setWidthRatio(double widthRatio) {
this.widthRatio = widthRatio;
}
public boolean isSquare() {
return this.isSquare;
}
public boolean isWrap() {
return isWrap;
}
public void setWrap(boolean wrap) {
isWrap = wrap;
}
public void setSwipeEnabled(boolean isSwipeable) {
this.isSwipeable = isSwipeable;
}
/**
* Override the Scroller instance with our own class so we can change the
* duration
*/
private void postInitViewPager() {
try {
Field scroller = ViewPager.class.getDeclaredField("mScroller");
scroller.setAccessible(true);
Field interpolator = ViewPager.class.getDeclaredField("sInterpolator");
interpolator.setAccessible(true);
mScroller = new ScrollerCustomDuration(getContext(),
(Interpolator) interpolator.get(null));
scroller.set(this, mScroller);
} catch (Exception e) {
}
}
private void initSwipeMethods() {
if (mSwipeOrientation == VERTICAL) {
// The majority of the work is done over here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}
}
/**
* Set the factor by which the duration will change
*/
public void setScrollDurationFactor(double scrollFactor) {
mScroller.setScrollDurationFactor(scrollFactor);
}
public int measureFragment(View view) {
if (view == null)
return 0;
view.measure(0, 0);
return view.getMeasuredHeight();
}
/**
* Determines the height of this view
*
* @param measureSpec A measureSpec packed into an int
* @param view the base view with already measured height
* @return The height of the view, honoring constraints from measureSpec
*/
private int measureHeight(int measureSpec, View view) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
// set the height from the base view if available
if (view != null) {
result = view.getMeasuredHeight();
}
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
/**
* Determines the width of this view
*
* @param measureSpec A measureSpec packed into an int
* @param view the base view with already measured width
* @return The height of the view, honoring constraints from measureSpec
*/
private int measureWidth(int measureSpec, View view) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
// set the height from the base view if available
if (view != null) {
result = view.getMeasuredWidth();
}
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}
private MotionEvent swapXY(MotionEvent event) {
float width = getWidth();
float height = getHeight();
float newX = (event.getY() / height) * width;
float newY = (event.getX() / width) * height;
event.setLocation(newX, newY);
return event;
}
private class VerticalPageTransformer implements ViewPager.PageTransformer {
@Override
public void transformPage(View page, float position) {
if (position < -1) {
// This page is way off-screen to the left
page.setAlpha(0);
} else if (position <= 1) {
page.setAlpha(1);
// Counteract the default slide transition
page.setTranslationX(page.getWidth() * -position);
// set Y position to swipe in from top
float yPosition = position * page.getHeight();
page.setTranslationY(yPosition);
} else {
// This page is way off screen to the right
page.setAlpha(0);
}
}
}
}
And in PagerAdapter
, I am using this piece of code to get measurement
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
if (position != mCurrentPosition) {
View view = (View) object;
CustomViewPager pager = (CustomViewPager) container;
if (null != view) {
mCurrentPosition = position;
pager.measureCurrentView(view);
}
}
Hi, when I use this solution with PagerTransformer - views inside viewpager are not updated until page is scrolled. Any advices on how can I solve it?