ViewPager.PageTransformer Android
ViewPager.PageTransformer Android
我想执行以下操作,
在 ViewPager 内的 ScrollVIew 内使用 GridLayout 创建图像网格,假设我有几页图片,第 1 页是动物,第 2 页是植物等。我希望能够上下滚动以查看图像,第 1 页上的动物,然后左右滚动以使用 PageTransformer 动画更改页面。我还需要按照 here 所述查看左右页面。现在我完成了所有这些,但是我无法解决触摸事件中的冲突,这就是我需要你帮助的地方。
现在,当我使用 pager.setPageTransformer(true, new ZoomOutPageTransformer());
时,我失去了 ScrollView 的上下滚动,我得到了很酷的动画。当我不使用它时,我得到了除了动画之外我需要的一切,我怎样才能得到它们?
这是我的主要activity,
public class MainActivity extends Activity {
PagerContainer mContainer;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContainer = (PagerContainer) findViewById(R.id.pager_container);
final 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(20);
//If hardware acceleration is enabled, you should also remove
// clipping on the pager for its children.
pager.setClipChildren(false);
pager.setPageTransformer(true, new ZoomOutPageTransformer());
}
//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) {
LinearLayout layout = new LinearLayout(container.getContext());
layout.setOrientation(LinearLayout.VERTICAL);
layout.setLayoutParams(new LinearLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT));
ScrollView sv=new ScrollView(container.getContext());
GridLayout gl = new GridLayout(container.getContext());
gl.setLayoutParams(new ViewGroup.LayoutParams ( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
gl.setOrientation(GridLayout.HORIZONTAL);
gl.setColumnCount(3);
gl.setRowCount(3);
for(int i=0;i<9;i++) {
ImageView imgView = new ImageView(container.getContext());
imgView.setImageResource(R.drawable.ic_launcher);
gl.addView( imgView);
}
sv.setVerticalScrollBarEnabled(false);
sv.addView(gl);
container.addView(sv);
return sv;
}
@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);
}
}
}
我的页面转换器是这样的,
public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.85f;
private static final float MIN_ALPHA = 0.5f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(MIN_ALPHA);
view.setScaleX(MIN_SCALE);
view.setScaleY(MIN_SCALE);
} else if (position <= 1) { // [-1,1]
// Modify the default slide transition to shrink the page as well
float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
} else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
// Scale the page down (between MIN_SCALE and 1)
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
// Fade the page relative to its size.
view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
view.clearAnimation();
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(MIN_ALPHA);
view.setScaleX(MIN_SCALE);
view.setScaleY(MIN_SCALE);
}
}
}
最后我的页面容器是这样的,
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);
}
}
我在看了 this 之后想通了,我的想法是你不需要使用这个 pager.setPageTransformer(true, new ZoomOutPageTransformer());
,并从我之前提到的 link 中复制一些东西, 并将 ZoomOutPageTransformer
作为函数放入容器中,因为您将在其中进行转换,最终代码如下。
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
final int scrollX = mPager.getScrollX();
final int childCount = mPager.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = mPager.getChildAt(i);
final ViewPager.LayoutParams lp = (ViewPager.LayoutParams) child.getLayoutParams();
if (lp.isDecor) continue;
final float transformPos = (float) (child.getLeft() - scrollX) / child.getWidth();
transformPage(child, transformPos);
}
if (mNeedsRedraw) invalidate();
}
@Override
public void onPageSelected(int position) {
// mPager. getChildAt(3).setAlpha(05f);
}
@Override
public void onPageScrollStateChanged(int state) {
mNeedsRedraw = (state != ViewPager.SCROLL_STATE_IDLE);
}
private static final float MIN_SCALE = 0.85f;
private static final float MIN_ALPHA = 0.5f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
// view.setAlpha(MIN_ALPHA);
view.setScaleX(MIN_SCALE);
view.setScaleY(MIN_SCALE);
} else if (position <= 1) { // [-1,1]
// Modify the default slide transition to shrink the page as well
float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
} else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
// Scale the page down (between MIN_SCALE and 1)
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
// Fade the page relative to its size.
// view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
view.clearAnimation();
} else { // (1,+Infinity]
// This page is way off-screen to the right.
// view.setAlpha(MIN_ALPHA);
view.setScaleX(MIN_SCALE);
view.setScaleY(MIN_SCALE);
}
}
}
只使用上面的 PagerContainer 和 MainActivity,不要伪造禁用 setPageTransformer 就可以了。
我想执行以下操作,
在 ViewPager 内的 ScrollVIew 内使用 GridLayout 创建图像网格,假设我有几页图片,第 1 页是动物,第 2 页是植物等。我希望能够上下滚动以查看图像,第 1 页上的动物,然后左右滚动以使用 PageTransformer 动画更改页面。我还需要按照 here 所述查看左右页面。现在我完成了所有这些,但是我无法解决触摸事件中的冲突,这就是我需要你帮助的地方。
现在,当我使用 pager.setPageTransformer(true, new ZoomOutPageTransformer());
时,我失去了 ScrollView 的上下滚动,我得到了很酷的动画。当我不使用它时,我得到了除了动画之外我需要的一切,我怎样才能得到它们?
这是我的主要activity,
public class MainActivity extends Activity {
PagerContainer mContainer;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContainer = (PagerContainer) findViewById(R.id.pager_container);
final 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(20);
//If hardware acceleration is enabled, you should also remove
// clipping on the pager for its children.
pager.setClipChildren(false);
pager.setPageTransformer(true, new ZoomOutPageTransformer());
}
//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) {
LinearLayout layout = new LinearLayout(container.getContext());
layout.setOrientation(LinearLayout.VERTICAL);
layout.setLayoutParams(new LinearLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT));
ScrollView sv=new ScrollView(container.getContext());
GridLayout gl = new GridLayout(container.getContext());
gl.setLayoutParams(new ViewGroup.LayoutParams ( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
gl.setOrientation(GridLayout.HORIZONTAL);
gl.setColumnCount(3);
gl.setRowCount(3);
for(int i=0;i<9;i++) {
ImageView imgView = new ImageView(container.getContext());
imgView.setImageResource(R.drawable.ic_launcher);
gl.addView( imgView);
}
sv.setVerticalScrollBarEnabled(false);
sv.addView(gl);
container.addView(sv);
return sv;
}
@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);
}
}
}
我的页面转换器是这样的,
public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
private static final float MIN_SCALE = 0.85f;
private static final float MIN_ALPHA = 0.5f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(MIN_ALPHA);
view.setScaleX(MIN_SCALE);
view.setScaleY(MIN_SCALE);
} else if (position <= 1) { // [-1,1]
// Modify the default slide transition to shrink the page as well
float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
} else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
// Scale the page down (between MIN_SCALE and 1)
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
// Fade the page relative to its size.
view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
view.clearAnimation();
} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(MIN_ALPHA);
view.setScaleX(MIN_SCALE);
view.setScaleY(MIN_SCALE);
}
}
}
最后我的页面容器是这样的,
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);
}
}
我在看了 this 之后想通了,我的想法是你不需要使用这个 pager.setPageTransformer(true, new ZoomOutPageTransformer());
,并从我之前提到的 link 中复制一些东西, 并将 ZoomOutPageTransformer
作为函数放入容器中,因为您将在其中进行转换,最终代码如下。
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
final int scrollX = mPager.getScrollX();
final int childCount = mPager.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = mPager.getChildAt(i);
final ViewPager.LayoutParams lp = (ViewPager.LayoutParams) child.getLayoutParams();
if (lp.isDecor) continue;
final float transformPos = (float) (child.getLeft() - scrollX) / child.getWidth();
transformPage(child, transformPos);
}
if (mNeedsRedraw) invalidate();
}
@Override
public void onPageSelected(int position) {
// mPager. getChildAt(3).setAlpha(05f);
}
@Override
public void onPageScrollStateChanged(int state) {
mNeedsRedraw = (state != ViewPager.SCROLL_STATE_IDLE);
}
private static final float MIN_SCALE = 0.85f;
private static final float MIN_ALPHA = 0.5f;
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
// view.setAlpha(MIN_ALPHA);
view.setScaleX(MIN_SCALE);
view.setScaleY(MIN_SCALE);
} else if (position <= 1) { // [-1,1]
// Modify the default slide transition to shrink the page as well
float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
} else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
// Scale the page down (between MIN_SCALE and 1)
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
// Fade the page relative to its size.
// view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
view.clearAnimation();
} else { // (1,+Infinity]
// This page is way off-screen to the right.
// view.setAlpha(MIN_ALPHA);
view.setScaleX(MIN_SCALE);
view.setScaleY(MIN_SCALE);
}
}
}
只使用上面的 PagerContainer 和 MainActivity,不要伪造禁用 setPageTransformer 就可以了。