转载请声明出处http://blog.csdn.net/zhongkejingwang/article/details/38728119

之前自己做的一个APP需要用到翻页阅读,网上看过立体翻页效果,不过bug太多了还不兼容。看了一下多看阅读翻页是采用平移翻页的,于是就仿写了一个平移翻页的控件。效果如下:

在翻页时页面右边缘绘制了阴影,效果还不错。要实现这种平移翻页控件并不难,只需要定义一个布局管理页面就可以了。具体实现上有以下难点:

1、循环翻页,页面的重复利用。

2、在翻页时过滤掉多点触碰。

3、采用setAdapter的方式设置页面布局和数据。

下面就来一一解决这几个难点。首先看循环翻页问题,怎么样能采用较少的页面实现这种翻页呢?由于屏幕上每次只能显示一张完整的页面,翻过去的页面也看不到,所以可以把翻过去的页面拿来重复利用,不必每次都new一个页面,所以,我只用了三张页面实现循环翻页。要想重复利用页面,首先要知道页面在布局中序号和对应的层次关系,比如一个父控件的子view的序号越大就位于越上层。循环利用页面的原理图如下:

向右翻页时状态图是这样的,只用了0、1、2三张页面,页面序号为2的位于最上层,我把它隐藏在左边,所以看到的只有页面1,页面0在1下面挡着也看不到,向右翻页时,页面2被滑到屏幕中,这时候把页面0的内容替换成页面2的前一页内容,把它放到之前页面2的位置,这时,状态又回到了初始状态,又可以继续向右翻页了!

向左翻页时是这样的,初始状态还是一样,当页面1被往左翻过时,看到的是页面0,这时候页面0下面已经没有页面了,而页面2已经用不到了,这时候把页面2放到页面0下面,这时候状态又回到了初始状态,就可以继续往左翻页了。

类似于这种循环效果的实现我一直用的解决方案都是将选中的置于最中间,比如原理图中的页面1,每次翻页完成后可见的都是页面1。在滚动选择器PickerView中也是同样的方案。这就解决了页面的重复利用问题了。

解决难点2 翻页时过滤多点触碰这个问题在仿淘宝商品浏览界面中已经解决过了,就是用一个控制变量mEvents过滤掉pointer down或up后到来的第一个move事件。

解决难点3 采用adapter方式设置页面的布局和数据。这个在Android的AdapterView里用到的,但是我没有看它的adapter机制,太复杂了,我就搞了个简单的adapter,如下:

PageAdapter.java:

**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)
  <div>
    <embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_1">
    </embed>
  </div>
</div>
- <span class="keyword">package</span> com.jingchen.pagerdemo;

- 
- <span class="keyword">import</span> android.view.View;

- 
- <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> PageAdapter

- {

- <span class="comment">/**</span>

- <span class="comment">     * @return 页面view</span>

- <span class="comment">     */</span>

- <span class="keyword">public</span> <span class="keyword">abstract</span> View getView();

- 
- <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">int</span> getCount();

- 
- <span class="comment">/**</span>

- <span class="comment">     * 将内容添加到view中</span>

- <span class="comment">     * </span>

- <span class="comment">     * @param view</span>

- <span class="comment">     *            包含内容的view</span>

- <span class="comment">     * @param position</span>

- <span class="comment">     *            第position页</span>

- <span class="comment">     */</span>

- <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> addContent(View view, <span class="keyword">int</span> position);

- }

这是一个抽象类,getView()用于返回页面的布局,getCount()返回数据总共需要多少页,addContent(View view, int position)这个是每翻过一页后将会被调用来请求页面数据的,参数view就是页面,position是表明第几页。待会儿会在自定义布局中定义setAdapter方法设置设配器。

OK,难点都解决了,自定义一个布局叫ScanView继承自RelativeLayout:

ScanView.java:

**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)
  <div>
    <embed id="ZeroClipboardMovie_2" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_2">
    </embed>
  </div>
</div>
- <span class="keyword">package</span> com.jingchen.pagerdemo;

- 
- <span class="keyword">import</span> java.util.Timer;

- <span class="keyword">import</span> java.util.TimerTask;

- 
- <span class="keyword">import</span> android.content.Context;

- <span class="keyword">import</span> android.graphics.Canvas;

- <span class="keyword">import</span> android.graphics.LinearGradient;

- <span class="keyword">import</span> android.graphics.Paint;

- <span class="keyword">import</span> android.graphics.Paint.Style;

- <span class="keyword">import</span> android.graphics.RectF;

- <span class="keyword">import</span> android.graphics.Shader.TileMode;

- <span class="keyword">import</span> android.os.Handler;

- <span class="keyword">import</span> android.os.Message;

- <span class="keyword">import</span> android.util.AttributeSet;

- <span class="keyword">import</span> android.util.Log;

- <span class="keyword">import</span> android.view.MotionEvent;

- <span class="keyword">import</span> android.view.VelocityTracker;

- <span class="keyword">import</span> android.view.View;

- <span class="keyword">import</span> android.widget.RelativeLayout;

- 
- <span class="comment">/**</span>

- <span class="comment"> * @author chenjing</span>

- <span class="comment"> *</span>

- <span class="comment"> */</span>

- <span class="keyword">public</span> <span class="keyword">class</span> ScanView <span class="keyword">extends</span> RelativeLayout

- {

- <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String TAG = <span class="string">&#8220;ScanView&#8221;</span>;

- <span class="keyword">private</span> <span class="keyword">boolean</span> isInit = <span class="keyword">true</span>;

- <span class="comment">// 滑动的时候存在两页可滑动,要判断是哪一页在滑动</span>

- <span class="keyword">private</span> <span class="keyword">boolean</span> isPreMoving = <span class="keyword">true</span>, isCurrMoving = <span class="keyword">true</span>;

- <span class="comment">// 当前是第几页</span>

- <span class="keyword">private</span> <span class="keyword">int</span> index;

- <span class="keyword">private</span> <span class="keyword">float</span> lastX;

- <span class="comment">// 前一页,当前页,下一页的左边位置</span>

- <span class="keyword">private</span> <span class="keyword">int</span> prePageLeft = <span class="number"></span>, currPageLeft = <span class="number"></span>, nextPageLeft = <span class="number"></span>;

- <span class="comment">// 三张页面</span>

- <span class="keyword">private</span> View prePage, currPage, nextPage;

- <span class="comment">// 页面状态</span>

- <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> STATE_MOVE = <span class="number"></span>;

- <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> STATE_STOP = <span class="number">1</span>;

- <span class="comment">// 滑动的页面,只有前一页和当前页可滑</span>

- <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> PRE = <span class="number">2</span>;

- <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> CURR = <span class="number">3</span>;

- <span class="keyword">private</span> <span class="keyword">int</span> state = STATE_STOP;

- <span class="comment">// 正在滑动的页面右边位置,用于绘制阴影</span>

- <span class="keyword">private</span> <span class="keyword">float</span> right;

- <span class="comment">// 手指滑动的距离</span>

- <span class="keyword">private</span> <span class="keyword">float</span> moveLenght;

- <span class="comment">// 页面宽高</span>

- <span class="keyword">private</span> <span class="keyword">int</span> mWidth, mHeight;

- <span class="comment">// 获取滑动速度</span>

- <span class="keyword">private</span> VelocityTracker vt;

- <span class="comment">// 防止抖动</span>

- <span class="keyword">private</span> <span class="keyword">float</span> speed_shake = <span class="number">20</span>;

- <span class="comment">// 当前滑动速度</span>

- <span class="keyword">private</span> <span class="keyword">float</span> speed;

- <span class="keyword">private</span> Timer timer;

- <span class="keyword">private</span> MyTimerTask mTask;

- <span class="comment">// 滑动动画的移动速度</span>

- <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> MOVE_SPEED = <span class="number">10</span>;

- <span class="comment">// 页面适配器</span>

- <span class="keyword">private</span> PageAdapter adapter;

- <span class="comment">/**</span>

- <span class="comment">     * 过滤多点触碰的控制变量</span>

- <span class="comment">     */</span>

- <span class="keyword">private</span> <span class="keyword">int</span> mEvents;

- 
- <span class="keyword">public</span> <span class="keyword">void</span> setAdapter(ScanViewAdapter adapter)

- {

- removeAllViews();

- <span class="keyword">this</span>.adapter = adapter;

- prePage = adapter.getView();

- addView(prePage, <span class="number"></span>, <span class="keyword">new</span> LayoutParams(LayoutParams.MATCH_PARENT,

- LayoutParams.MATCH_PARENT));

- adapter.addContent(prePage, index &#8211; <span class="number">1</span>);

- 
- currPage = adapter.getView();

- addView(currPage, <span class="number"></span>, <span class="keyword">new</span> LayoutParams(LayoutParams.MATCH_PARENT,

- LayoutParams.MATCH_PARENT));

- adapter.addContent(currPage, index);

- 
- nextPage = adapter.getView();

- addView(nextPage, <span class="number"></span>, <span class="keyword">new</span> LayoutParams(LayoutParams.MATCH_PARENT,

- LayoutParams.MATCH_PARENT));

- adapter.addContent(nextPage, index + <span class="number">1</span>);

- 
- }

- 
- <span class="comment">/**</span>

- <span class="comment">     * 向左滑。注意可以滑动的页面只有当前页和前一页</span>

- <span class="comment">     * </span>

- <span class="comment">     * @param which</span>

- <span class="comment">     */</span>

- <span class="keyword">private</span> <span class="keyword">void</span> moveLeft(<span class="keyword">int</span> which)

- {

- <span class="keyword">switch</span> (which)

- {

- <span class="keyword">case</span> PRE:

- prePageLeft -= MOVE_SPEED;

- <span class="keyword">if</span> (prePageLeft < -mWidth)

- prePageLeft = -mWidth;

- right = mWidth + prePageLeft;

- <span class="keyword">break</span>;

- <span class="keyword">case</span> CURR:

- currPageLeft -= MOVE_SPEED;

- <span class="keyword">if</span> (currPageLeft < -mWidth)

- currPageLeft = -mWidth;

- right = mWidth + currPageLeft;

- <span class="keyword">break</span>;

- }

- }

- 
- <span class="comment">/**</span>

- <span class="comment">     * 向右滑。注意可以滑动的页面只有当前页和前一页</span>

- <span class="comment">     * </span>

- <span class="comment">     * @param which</span>

- <span class="comment">     */</span>

- <span class="keyword">private</span> <span class="keyword">void</span> moveRight(<span class="keyword">int</span> which)

- {

- <span class="keyword">switch</span> (which)

- {

- <span class="keyword">case</span> PRE:

- prePageLeft += MOVE_SPEED;

- <span class="keyword">if</span> (prePageLeft > <span class="number"></span>)

- prePageLeft = <span class="number"></span>;

- right = mWidth + prePageLeft;

- <span class="keyword">break</span>;

- <span class="keyword">case</span> CURR:

- currPageLeft += MOVE_SPEED;

- <span class="keyword">if</span> (currPageLeft > <span class="number"></span>)

- currPageLeft = <span class="number"></span>;

- right = mWidth + currPageLeft;

- <span class="keyword">break</span>;

- }

- }

- 
- <span class="comment">/**</span>

- <span class="comment">     * 当往回翻过一页时添加前一页在最左边</span>

- <span class="comment">     */</span>

- <span class="keyword">private</span> <span class="keyword">void</span> addPrePage()

- {

- removeView(nextPage);

- addView(nextPage, &#8211;<span class="number">1</span>, <span class="keyword">new</span> LayoutParams(LayoutParams.MATCH_PARENT,

- LayoutParams.MATCH_PARENT));

- <span class="comment">// 从适配器获取前一页内容</span>

- adapter.addContent(nextPage, index &#8211; <span class="number">1</span>);

- <span class="comment">// 交换顺序</span>

- View temp = nextPage;

- nextPage = currPage;

- currPage = prePage;

- prePage = temp;

- prePageLeft = -mWidth;

- }

- 
- <span class="comment">/**</span>

- <span class="comment">     * 当往前翻过一页时,添加一页在最底下</span>

- <span class="comment">     */</span>

- <span class="keyword">private</span> <span class="keyword">void</span> addNextPage()

- {

- removeView(prePage);

- addView(prePage, <span class="number"></span>, <span class="keyword">new</span> LayoutParams(LayoutParams.MATCH_PARENT,

- LayoutParams.MATCH_PARENT));

- <span class="comment">// 从适配器获取后一页内容</span>

- adapter.addContent(prePage, index + <span class="number">1</span>);

- <span class="comment">// 交换顺序</span>

- View temp = currPage;

- currPage = nextPage;

- nextPage = prePage;

- prePage = temp;

- currPageLeft = <span class="number"></span>;

- }

- 
- Handler updateHandler = <span class="keyword">new</span> Handler()

- {

- 
- <span class="annotation">@Override</span>

- <span class="keyword">public</span> <span class="keyword">void</span> handleMessage(Message msg)

- {

- <span class="keyword">if</span> (state != STATE_MOVE)

- <span class="keyword">return</span>;

- <span class="comment">// 移动页面</span>

- <span class="comment">// 翻回,先判断当前哪一页处于未返回状态</span>

- <span class="keyword">if</span> (prePageLeft > -mWidth && speed <= <span class="number"></span>)

- {

- <span class="comment">// 前一页处于未返回状态</span>

- moveLeft(PRE);

- } <span class="keyword">else</span> <span class="keyword">if</span> (currPageLeft < <span class="number"></span> && speed >= <span class="number"></span>)

- {

- <span class="comment">// 当前页处于未返回状态</span>

- moveRight(CURR);

- } <span class="keyword">else</span> <span class="keyword">if</span> (speed < <span class="number"></span> && index < adapter.getCount())

- {

- <span class="comment">// 向左翻,翻动的是当前页</span>

- moveLeft(CURR);

- <span class="keyword">if</span> (currPageLeft == (-mWidth))

- {

- index++;

- <span class="comment">// 翻过一页,在底下添加一页,把最上层页面移除</span>

- addNextPage();

- }

- } <span class="keyword">else</span> <span class="keyword">if</span> (speed > <span class="number"></span> && index > <span class="number">1</span>)

- {

- <span class="comment">// 向右翻,翻动的是前一页</span>

- moveRight(PRE);

- <span class="keyword">if</span> (prePageLeft == <span class="number"></span>)

- {

- index&#8211;;

- <span class="comment">// 翻回一页,添加一页在最上层,隐藏在最左边</span>

- addPrePage();

- }

- }

- <span class="keyword">if</span> (right == <span class="number"></span> || right == mWidth)

- {

- releaseMoving();

- state = STATE_STOP;

- quitMove();

- }

- ScanView.<span class="keyword">this</span>.requestLayout();

- }

- 
- };

- 
- <span class="keyword">public</span> ScanView(Context context, AttributeSet attrs, <span class="keyword">int</span> defStyle)

- {

- <span class="keyword">super</span>(context, attrs, defStyle);

- init();

- }

- 
- <span class="keyword">public</span> ScanView(Context context)

- {

- <span class="keyword">super</span>(context);

- init();

- }

- 
- <span class="keyword">public</span> ScanView(Context context, AttributeSet attrs)

- {

- <span class="keyword">super</span>(context, attrs);

- init();

- }

- 
- <span class="comment">/**</span>

- <span class="comment">     * 退出动画翻页</span>

- <span class="comment">     */</span>

- <span class="keyword">public</span> <span class="keyword">void</span> quitMove()

- {

- <span class="keyword">if</span> (mTask != <span class="keyword">null</span>)

- {

- mTask.cancel();

- mTask = <span class="keyword">null</span>;

- }

- }

- 
- <span class="keyword">private</span> <span class="keyword">void</span> init()

- {

- index = <span class="number">1</span>;

- timer = <span class="keyword">new</span> Timer();

- mTask = <span class="keyword">new</span> MyTimerTask(updateHandler);

- }

- 
- <span class="comment">/**</span>

- <span class="comment">     * 释放动作,不限制手滑动方向</span>

- <span class="comment">     */</span>

- <span class="keyword">private</span> <span class="keyword">void</span> releaseMoving()

- {

- isPreMoving = <span class="keyword">true</span>;

- isCurrMoving = <span class="keyword">true</span>;

- }

- 
- <span class="annotation">@Override</span>

- <span class="keyword">public</span> <span class="keyword">boolean</span> dispatchTouchEvent(MotionEvent event)

- {

- <span class="keyword">if</span> (adapter != <span class="keyword">null</span>)

- <span class="keyword">switch</span> (event.getActionMasked())

- {

- <span class="keyword">case</span> MotionEvent.ACTION_DOWN:

- lastX = event.getX();

- <span class="keyword">try</span>

- {

- <span class="keyword">if</span> (vt == <span class="keyword">null</span>)

- {

- vt = VelocityTracker.obtain();

- } <span class="keyword">else</span>

- {

- vt.clear();

- }

- } <span class="keyword">catch</span> (Exception e)

- {

- e.printStackTrace();

- }

- vt.addMovement(event);

- mEvents = <span class="number"></span>;

- <span class="keyword">break</span>;

- <span class="keyword">case</span> MotionEvent.ACTION_POINTER_DOWN:

- <span class="keyword">case</span> MotionEvent.ACTION_POINTER_UP:

- mEvents = &#8211;<span class="number">1</span>;

- <span class="keyword">break</span>;

- <span class="keyword">case</span> MotionEvent.ACTION_MOVE:

- <span class="comment">// 取消动画</span>

- quitMove();

- Log.d(<span class="string">&#8220;index&#8221;</span>, <span class="string">&#8220;mEvents = &#8220;</span> + mEvents + <span class="string">&#8220;, isPreMoving = &#8220;</span>

- + isPreMoving + <span class="string">&#8220;, isCurrMoving = &#8220;</span> + isCurrMoving);

- vt.addMovement(event);

- vt.computeCurrentVelocity(<span class="number">500</span>);

- speed = vt.getXVelocity();

- moveLenght = event.getX() &#8211; lastX;

- <span class="keyword">if</span> ((moveLenght > <span class="number"></span> || !isCurrMoving) && isPreMoving

- && mEvents == <span class="number"></span>)

- {

- isPreMoving = <span class="keyword">true</span>;

- isCurrMoving = <span class="keyword">false</span>;

- <span class="keyword">if</span> (index == <span class="number">1</span>)

- {

- <span class="comment">// 第一页不能再往右翻,跳转到前一个activity</span>

- state = STATE_MOVE;

- releaseMoving();

- } <span class="keyword">else</span>

- {

- <span class="comment">// 非第一页</span>

- prePageLeft += (<span class="keyword">int</span>) moveLenght;

- <span class="comment">// 防止滑过边界</span>

- <span class="keyword">if</span> (prePageLeft > <span class="number"></span>)

- prePageLeft = <span class="number"></span>;

- <span class="keyword">else</span> <span class="keyword">if</span> (prePageLeft < -mWidth)

- {

- <span class="comment">// 边界判断,释放动作,防止来回滑动导致滑动前一页时当前页无法滑动</span>

- prePageLeft = -mWidth;

- releaseMoving();

- }

- right = mWidth + prePageLeft;

- state = STATE_MOVE;

- }

- } <span class="keyword">else</span> <span class="keyword">if</span> ((moveLenght < <span class="number"></span> || !isPreMoving) && isCurrMoving

- && mEvents == <span class="number"></span>)

- {

- isPreMoving = <span class="keyword">false</span>;

- isCurrMoving = <span class="keyword">true</span>;

- <span class="keyword">if</span> (index == adapter.getCount())

- {

- <span class="comment">// 最后一页不能再往左翻</span>

- state = STATE_STOP;

- releaseMoving();

- } <span class="keyword">else</span>

- {

- currPageLeft += (<span class="keyword">int</span>) moveLenght;

- <span class="comment">// 防止滑过边界</span>

- <span class="keyword">if</span> (currPageLeft < -mWidth)

- currPageLeft = -mWidth;

- <span class="keyword">else</span> <span class="keyword">if</span> (currPageLeft > <span class="number"></span>)

- {

- <span class="comment">// 边界判断,释放动作,防止来回滑动导致滑动当前页是前一页无法滑动</span>

- currPageLeft = <span class="number"></span>;

- releaseMoving();

- }

- right = mWidth + currPageLeft;

- state = STATE_MOVE;

- }

- 
- } <span class="keyword">else</span>

- mEvents = <span class="number"></span>;

- lastX = event.getX();

- requestLayout();

- <span class="keyword">break</span>;

- <span class="keyword">case</span> MotionEvent.ACTION_UP:

- <span class="keyword">if</span> (Math.abs(speed) < speed_shake)

- speed = <span class="number"></span>;

- quitMove();

- mTask = <span class="keyword">new</span> MyTimerTask(updateHandler);

- timer.schedule(mTask, <span class="number"></span>, <span class="number">5</span>);

- <span class="keyword">try</span>

- {

- vt.clear();

- vt.recycle();

- } <span class="keyword">catch</span> (Exception e)

- {

- e.printStackTrace();

- }

- <span class="keyword">break</span>;

- <span class="keyword">default</span>:

- <span class="keyword">break</span>;

- }

- <span class="keyword">super</span>.dispatchTouchEvent(event);

- <span class="keyword">return</span> <span class="keyword">true</span>;

- }

- 
- <span class="comment">/*</span>

- <span class="comment">     * (非 Javadoc) 在这里绘制翻页阴影效果</span>

- <span class="comment">     * </span>

- <span class="comment">     * @see android.view.ViewGroup#dispatchDraw(android.graphics.Canvas)</span>

- <span class="comment">     */</span>

- <span class="annotation">@Override</span>

- <span class="keyword">protected</span> <span class="keyword">void</span> dispatchDraw(Canvas canvas)

- {

- <span class="keyword">super</span>.dispatchDraw(canvas);

- <span class="keyword">if</span> (right == <span class="number"></span> || right == mWidth)

- <span class="keyword">return</span>;

- RectF rectF = <span class="keyword">new</span> RectF(right, <span class="number"></span>, mWidth, mHeight);

- Paint paint = <span class="keyword">new</span> Paint();

- paint.setAntiAlias(<span class="keyword">true</span>);

- LinearGradient linearGradient = <span class="keyword">new</span> LinearGradient(right, <span class="number"></span>,

- right + <span class="number">36</span>, <span class="number"></span>, <span class="number">0xffbbbbbb</span>, <span class="number">0x00bbbbbb</span>, TileMode.CLAMP);

- paint.setShader(linearGradient);

- paint.setStyle(Style.FILL);

- canvas.drawRect(rectF, paint);

- }

- 
- <span class="annotation">@Override</span>

- <span class="keyword">protected</span> <span class="keyword">void</span> onMeasure(<span class="keyword">int</span> widthMeasureSpec, <span class="keyword">int</span> heightMeasureSpec)

- {

- <span class="keyword">super</span>.onMeasure(widthMeasureSpec, heightMeasureSpec);

- mWidth = getMeasuredWidth();

- mHeight = getMeasuredHeight();

- <span class="keyword">if</span> (isInit)

- {

- <span class="comment">// 初始状态,一页放在左边隐藏起来,两页叠在一块</span>

- prePageLeft = -mWidth;

- currPageLeft = <span class="number"></span>;

- nextPageLeft = <span class="number"></span>;

- isInit = <span class="keyword">false</span>;

- }

- }

- 
- <span class="annotation">@Override</span>

- <span class="keyword">protected</span> <span class="keyword">void</span> onLayout(<span class="keyword">boolean</span> changed, <span class="keyword">int</span> l, <span class="keyword">int</span> t, <span class="keyword">int</span> r, <span class="keyword">int</span> b)

- {

- <span class="keyword">if</span> (adapter == <span class="keyword">null</span>)

- <span class="keyword">return</span>;

- prePage.layout(prePageLeft, <span class="number"></span>,

- prePageLeft + prePage.getMeasuredWidth(),

- prePage.getMeasuredHeight());

- currPage.layout(currPageLeft, <span class="number"></span>,

- currPageLeft + currPage.getMeasuredWidth(),

- currPage.getMeasuredHeight());

- nextPage.layout(nextPageLeft, <span class="number"></span>,

- nextPageLeft + nextPage.getMeasuredWidth(),

- nextPage.getMeasuredHeight());

- invalidate();

- }

- 
- <span class="keyword">class</span> MyTimerTask <span class="keyword">extends</span> TimerTask

- {

- Handler handler;

- 
- <span class="keyword">public</span> MyTimerTask(Handler handler)

- {

- <span class="keyword">this</span>.handler = handler;

- }

- 
- <span class="annotation">@Override</span>

- <span class="keyword">public</span> <span class="keyword">void</span> run()

- {

- handler.sendMessage(handler.obtainMessage());

- }

- 
- }

- }

代码中的注释写的非常多,原理理解了看代码就容易看懂了。写完这个布局后再写一个ScanViewAdapter继承PageAdapter:

**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)
  <div>
    <embed id="ZeroClipboardMovie_3" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_3">
    </embed>
  </div>
</div>
- <span class="keyword">package</span> com.jingchen.pagerdemo;

- 
- <span class="keyword">import</span> java.util.List;

- 
- <span class="keyword">import</span> android.content.Context;

- <span class="keyword">import</span> android.content.res.AssetManager;

- <span class="keyword">import</span> android.graphics.Typeface;

- <span class="keyword">import</span> android.view.LayoutInflater;

- <span class="keyword">import</span> android.view.View;

- <span class="keyword">import</span> android.widget.TextView;

- 
- <span class="keyword">public</span> <span class="keyword">class</span> ScanViewAdapter <span class="keyword">extends</span> PageAdapter

- {

- Context context;

- List<String> items;

- AssetManager am;

- 
- <span class="keyword">public</span> ScanViewAdapter(Context context, List<String> items)

- {

- <span class="keyword">this</span>.context = context;

- <span class="keyword">this</span>.items = items;

- am = context.getAssets();

- }

- 
- <span class="keyword">public</span> <span class="keyword">void</span> addContent(View view, <span class="keyword">int</span> position)

- {

- TextView content = (TextView) view.findViewById(R.id.content);

- TextView tv = (TextView) view.findViewById(R.id.index);

- <span class="keyword">if</span> ((position &#8211; <span class="number">1</span>) < <span class="number"></span> || (position &#8211; <span class="number">1</span>) >= getCount())

- <span class="keyword">return</span>;

- content.setText(<span class="string">&#8221;    双峰叠障,过天风海雨,无边空碧。月姊年年应好在,玉阙琼宫愁寂。谁唤痴云,一杯未尽,夜气寒无色。碧城凝望,高楼缥缈西北。\n\n    肠断桂冷蟾孤,佳期如梦,又把阑干拍。雾鬓风虔相借问,浮世几回今夕。圆缺睛明,古今同恨,我更长为客。蝉娟明夜,尊前谁念南陌。&#8221;</span>);

- tv.setText(items.get(position &#8211; <span class="number">1</span>));

- }

- 
- <span class="keyword">public</span> <span class="keyword">int</span> getCount()

- {

- <span class="keyword">return</span> items.size();

- }

- 
- <span class="keyword">public</span> View getView()

- {

- View view = LayoutInflater.from(context).inflate(R.layout.page_layout,

- <span class="keyword">null</span>);

- <span class="keyword">return</span> view;

- }

- }

这里只是我的demo里写的Adapter,也可以写成带更多内容的Adapter。addContent里带的参数view就是getView里面返回的view,这样就可以根据inflate的布局设置内容了,getView返回的布局page_layout.xml如下:

**[html]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)
  <div>
    <embed id="ZeroClipboardMovie_4" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_4">
    </embed>
  </div>
</div>
- <span class="tag"><</span><span class="tag-name">RelativeLayout</span> <span class="attribute">xmlns:android</span>=<span class="attribute-value">&#8220;http://schemas.android.com/apk/res/android&#8221;</span>

- <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span>

- <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span>

- <span class="attribute">android:background</span>=<span class="attribute-value">&#8220;@drawable/cover&#8221;</span> <span class="tag">></span>

- 
- <span class="tag"><</span><span class="tag-name">TextView</span>

- <span class="attribute">android:id</span>=<span class="attribute-value">&#8220;@+id/content&#8221;</span>

- <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;wrap_content&#8221;</span>

- <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;wrap_content&#8221;</span>

- <span class="attribute">android:layout_centerHorizontal</span>=<span class="attribute-value">&#8220;true&#8221;</span>

- <span class="attribute">android:layout_marginTop</span>=<span class="attribute-value">&#8220;60dp&#8221;</span>

- <span class="attribute">android:padding</span>=<span class="attribute-value">&#8220;10dp&#8221;</span>

- <span class="attribute">android:textColor</span>=<span class="attribute-value">&#8220;#000000&#8221;</span>

- <span class="attribute">android:textSize</span>=<span class="attribute-value">&#8220;22sp&#8221;</span> <span class="tag">/></span>

- 
- <span class="tag"><</span><span class="tag-name">TextView</span>

- <span class="attribute">android:id</span>=<span class="attribute-value">&#8220;@+id/index&#8221;</span>

- <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;wrap_content&#8221;</span>

- <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;wrap_content&#8221;</span>

- <span class="attribute">android:layout_alignParentBottom</span>=<span class="attribute-value">&#8220;true&#8221;</span>

- <span class="attribute">android:layout_centerHorizontal</span>=<span class="attribute-value">&#8220;true&#8221;</span>

- <span class="attribute">android:layout_marginBottom</span>=<span class="attribute-value">&#8220;60dp&#8221;</span>

- <span class="attribute">android:textColor</span>=<span class="attribute-value">&#8220;#000000&#8221;</span>

- <span class="attribute">android:textSize</span>=<span class="attribute-value">&#8220;30sp&#8221;</span> <span class="tag">/></span>

- 
- <span class="tag"></</span><span class="tag-name">RelativeLayout</span><span class="tag">></span>

只包含了两个TextView,所以在adapter中可以根据id查找到这两个TextView再给它设置内容。

OK了,MainActivity的布局如下:

**[html]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)
  <div>
    <embed id="ZeroClipboardMovie_5" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_5">
    </embed>
  </div>
</div>
- <span class="tag"><</span><span class="tag-name">RelativeLayout</span> <span class="attribute">xmlns:android</span>=<span class="attribute-value">&#8220;http://schemas.android.com/apk/res/android&#8221;</span>

- <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span>

- <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span> <span class="tag">></span>

- 
- <span class="tag"><</span><span class="tag-name">com.jingchen.pagerdemo.ScanView</span>

- <span class="attribute">android:id</span>=<span class="attribute-value">&#8220;@+id/scanview&#8221;</span>

- <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span>

- <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span> <span class="tag">/></span>

- 
- <span class="tag"></</span><span class="tag-name">RelativeLayout</span><span class="tag">></span>

很简单,只包含了ScanView。

MainActivity的代码:

**[java]** [view plain](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)[copy](http://blog.csdn.net/zhongkejingwang/article/details/38728119#)
  <div>
    <embed id="ZeroClipboardMovie_6" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_6">
    </embed>
  </div>
</div>
- <span class="keyword">package</span> com.jingchen.pagerdemo;

- 
- <span class="keyword">import</span> java.util.ArrayList;

- <span class="keyword">import</span> java.util.List;

- 
- <span class="keyword">import</span> android.app.Activity;

- <span class="keyword">import</span> android.os.Bundle;

- <span class="keyword">import</span> android.view.Menu;

- 
- <span class="keyword">public</span> <span class="keyword">class</span> MainActivity <span class="keyword">extends</span> Activity

- {

- ScanView scanview;

- ScanViewAdapter adapter;

- 
- <span class="annotation">@Override</span>

- <span class="keyword">protected</span> <span class="keyword">void</span> onCreate(Bundle savedInstanceState)

- {

- <span class="keyword">super</span>.onCreate(savedInstanceState);

- setContentView(R.layout.activity_main);

- scanview = (ScanView) findViewById(R.id.scanview);

- List<String> items = <span class="keyword">new</span> ArrayList<String>();

- <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number"></span>; i < <span class="number">8</span>; i++)

- items.add(<span class="string">&#8220;第 &#8220;</span> + (i + <span class="number">1</span>) + <span class="string">&#8221; 页&#8221;</span>);

- adapter = <span class="keyword">new</span> ScanViewAdapter(<span class="keyword">this</span>, items);

- scanview.setAdapter(adapter);

- }

- 
- <span class="annotation">@Override</span>

- <span class="keyword">public</span> <span class="keyword">boolean</span> onCreateOptionsMenu(Menu menu)

- {

- getMenuInflater().inflate(R.menu.main, menu);

- <span class="keyword">return</span> <span class="keyword">true</span>;

- }

- 
- }

给ScanView设置Adapter就可以了。

好啦,仿多看的平移翻页就完成了~

源码下载

💬 评论