1. 云栖社区>
  2. 博客列表>
  3. 正文

ViewPager的两种特殊扩展及其他

振威 2016-11-23 19:07:00 浏览101 评论0

void page view ViewPager

摘要: 竖向滑动 ### 1.监听ViewPager的touch事件,交换touch的x和y坐标 private MotionEvent swapTouchEvent(MotionEvent event) { float width = getWidth(); float height = getHeight(); float swappedX = (event.

竖向滑动

### 1.监听ViewPager的touch事件,交换touch的x和y坐标

private MotionEvent swapTouchEvent(MotionEvent event) {
    float width = getWidth();
    float height = getHeight();

    float swappedX = (event.getY() / height) * width;
    float swappedY = (event.getX() / width) * height;

    event.setLocation(swappedX, swappedY);

    return event;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    boolean intercept = super.onInterceptTouchEvent(swapTouchEvent(ev));
    swapTouchEvent(ev);
    return intercept;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    return super.onTouchEvent(swapTouchEvent(ev));

}

###2.给ViewPager设置PageTransformer

public class VerticalTransformer implements ViewPager.PageTransformer {
    private float yPosition;

    @Override
    public void transformPage(View view, float position) {
        view.setTranslationX(view.getWidth() * -position);
        yPosition = position * view.getHeight();
        view.setTranslationY(yPosition);
    }
}

###3.Done and enjoy

============================

一屏内显示多页

一屏内显示多页的实现方式有两种,通过给ViewPager设置setPageMargin实现和通过覆写PagerAdapter的getPageWidth实现。

1.setPageMargin

#### 实现方法 通过viewpager.setPageMargin(int marginPixels),给ViewPager的每页设置一个负数的margin,然后在每一页的View留足够的空白给这个负值,来达到一屏显示多页的目的。
#### 原理 如图,此时的ViewPager是满屏的大小,通过给ViewPager设置负的PageMargin,使得下一页的内容和上一页有了一个重叠区域,而PageContainer是一个透明的View,作用是留出足够的空白给PageMargin这个值做重叠,为什么说足够的空白,因为还需要考虑到设置PageMargin之后的两页之间的间隔。

ViewPager
+--------------------------------------------------------+
| +---------------------------------------------------+  |
| |PageContainer          |重|   PageContainer        |  |
| |                       |  |                        |  |
| |   +-----------------+ |叠| +-----------------+    |  |
| |   |Actual View      | |  | |                 |    |  |
| |   |                 | |  | |                 |    |  |
| |   |                 | |区| |                 |    |  |
| |   |                 | |  | |                 |    |  |
| |   +-----------------+ |  | +-----------------+    |  |
| |                       |域|                        |  |
| |                       |  |                        |  |
| +---------------------------------------------------+  |
+--------------------------------------------------------+

带来的问题

使用这个方法会带来一个的体验上的问题(ViewPager本身的滑动是有一个判断的,拖动某一页过了一个定值,大概是一页PageContainer的一半,松手会滑到下一页)向右翻了几页后,向左翻页这个定值会异常,这个值会接近一个PageContainer的大小,带来的实际体验上的问题是,本来向左稍微滑动可以达到的翻页效果,现在几乎要把这一页完全翻过才能达到,体验上会有一点奇怪。

2.getPageWidth

#### 实现方法 通过重写PagerAdapter的getPageWidth方法,此方法返回的是ViewPager中每一页占实际ViewPager的宽度百分比,默认是1,即100%:

/**
 * Returns the proportional width of a given page as a percentage of the
 * ViewPager's measured width from (0.f-1.f]
 *
 * @param position The position of the page requested
 * @return Proportional width for the given page position
 */
public float getPageWidth(int position) {
    return 1.f;
}

带来的问题

相较上一种setPageMargin的方法来说,也许不算个问题,只是和原始ViewPager体验上的不一样。通过getPageWidth实现的ViewPager,滑动时会始终保持focus的页居左,如图:

ViewPager
+----------------------------------------------------+
|                                                    |
+----------------------------+ +---------------------+
||Page                       | |Page                 |
||                           | |                     |
||                           | |                     |
||                           | |                     |
||                           | |                     |
||                           | |                     |
||                           | |                     |
+----------------------------+ +---------------------+
|                                                    |
+----------------------------------------------------+

而滑动到最后一页时,会有如下图效果,即focus是最后一页时,最后一页不会保持居左,而是会在保证最后一页完全显示的情况下向左滑动一定值,效果及体验见天猫客户端首页。

 ViewPager
+------------------------------------------------------+
|                                                      |
+---------------------+ +----------------------------+ |
|Page                 | |Page                        | |
|                     | |                            | |
|                     | |                            | |
|                     | |                            | |
|                     | |                            | |
|                     | |                            | |
|                     | |                            | |
|                     | |                            | |
+---------------------+ +----------------------------+ |
|                                                      |
+------------------------------------------------------+

========================

ViewPager作为轮播Banner时需要注意的点

这里提到的场景比较特殊,一是轮播Banner,轮播Banner的特点是有一个timer计时器用于计算何时翻到下一页,二是用在了有复用和回收的地方,如ListView和RecyclerView。
常见的优化是,在ViewPager滑出屏幕时需要停止timer,再次滑入屏幕时需要启动timer;需要覆写ViewPager里的一些方法实现,但是不一定能都覆盖到,集思广益,先说我暂时收集到的:

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    startTimer();
}

@Override
protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    stopTimer();
}

@Override
protected void onVisibilityChanged(View changedView, int visibility) {
    super.onVisibilityChanged(changedView, visibility);
    if (visibility == VISIBLE) {
        startTimer();
    } else {
        stopTimer();
    }
}

@Override
public void onStartTemporaryDetach() {
    super.onStartTemporaryDetach();
    stopTimer();
}

@Override
public void onFinishTemporaryDetach() {
    super.onFinishTemporaryDetach();
    startTimer();
}

这里比较常见的是前三个方法,即在被附加和从Window上移除时,可见性发生改变时;
关于后两个方法,先贴源码(取自View.java):

```java /** * This is called when a container is going to temporarily detach a child, with * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. * It will either be followed by {@link #onFinishTemporaryDetach()} or * {@link #onDetachedFromWindow()} when the container is done. */ public void onStartTemporaryDetach() { removeUnsetPressCallback(); mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; }

/** * Called after {@link #onStartTemporaryDetach} when the container is done * changing the view. */ public void onFinishTemporaryDetach() { } ``` 
onStartTemporaryDetach和onFinishTemporaryDetach是成对出现的方法,在Parent需要对此View作出调整的时候会触发onStartTemporaryDetach,同时结束后调用onFinishTemporaryDetach。

用云栖社区APP,舒服~

【云栖快讯】最强攻略!10分钟上手阿里云产品,快速搭建自己的专属网站。云服务器配置选型、实例创建、搭建云端网站、云数据库操作、玩转云存储,统统不在话下。  详情请点击

网友评论

为您提供简单高效、处理能力可弹性伸缩的计算服务,帮助您快速构建更稳定、安全的应用,提升运维效率,降低 IT 成本...

RDS是一种稳定可靠、可弹性伸缩的在线数据库服务。支持MySQL、SQL Server、PostgreSQL、高...
从春运抢票到相亲,春节背后的这些技术,你知道多少?

从春运抢票到相亲,春节背后的这些技术,你知道多少?