先上效果图:
实现“左右滑屏”核心类是Scroller,将View中的内容左右滚动从而实现滑屏效果。关键方法有:
scroller.scrollTo(x,y):
直接将View中的内容滚动到指定的(x,y)位置。
scroller.scrollTo(dx,dy):
直接将View中的内容滚动到相对当前状态的(dx,dy)位置。本例中用于实现手指拖拉移动View的效果。
scroller.startScroll(nowX, nowY, moveX, moveY, duration):
在duration的时间内完成move的位移。配合重写View.computeScroll()不断刷新界面从而实现滑屏动画。
如果当前点击拖拉的组件是按钮等自身可处理手势动作的组件,则重写ViewGroup.onInterceptTouchEvent(MotionEvent)可拦截此事件并将此事件传递至onTouchEvent(MotionEvent)进行处理。从而对如按钮等即可点击亦可拖拉。
左右滑屏的指示器位置为SlidingIndicator。在fadeOut()方法中为本组件的
animFadeout.setStartTime(AnimationUtils.currentAnimationTimeMillis() + fadeDelay);
setAnimation(animFadeout);
package lab.sodino.sliding;
import lab.sodino.sliding.SlidingContainer.OnSlidingListener;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class ActSlidingContainer extends Activity implements OnClickListener, OnSlidingListener {
private SlidingContainer slidingContainer;
private SlidingIndicator slidingIndicator;
private Button btnLeft, btnRight, btnMid;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnLeft = (Button) findViewById(R.id.left);
btnLeft.setOnClickListener(this);
btnRight = (Button) findViewById(R.id.right);
btnRight.setOnClickListener(this);
btnMid = (Button) findViewById(R.id.mid);
btnMid.setOnClickListener(this);
slidingContainer = (SlidingContainer) findViewById(R.id.slidingContainer);
slidingContainer.setOnSlidingListener(this);
slidingIndicator = (SlidingIndicator) findViewById(R.id.slidingIndicator);
slidingIndicator.setPageAmount(slidingContainer.getChildCount());
}
@Override
public void onClick(View v) {
if (v == btnLeft) {
slidingContainer.scroll2page(slidingContainer.getCurrentPage() - 1);
} else if (v == btnRight) {
slidingContainer.scroll2page(slidingContainer.getCurrentPage() + 1);
} else if (v == btnMid) {
slidingContainer.scroll2page(slidingContainer.getChildCount() >> 1);
}
}
@Override
public void onSliding(int scrollX) {
float scale = (float) (slidingContainer.getPageWidth() * slidingContainer.getChildCount())
/ (float) slidingIndicator.getWidth();
slidingIndicator.setPosition((int) (scrollX / scale));
}
@Override
public void onSlidingEnd(int pageIdx, int scrollX) {
slidingIndicator.setCurrentPage(pageIdx);
}
}
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a><div style="position: absolute; left: 0px; top: 0px; 0px; height: 0px; z-index: 99;"><embed id="ZeroClipboardMovie_4" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="0" height="0" name="ZeroClipboardMovie_4" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=4&width=0&height=0" wmode="transparent"></div></div></div><ol start="1" class="dp-j"><li class="alt"><span><span><pre></pre> </span></span></li><li class=""><span><p></p> </span></li><li class="alt"><span><p></p> </span></li><li class=""><span><p>SlidingContainer.java</p> </span></li><li class="alt"><span><pre name=<span class="string">"code"</span><span> </span><span class="keyword">class</span><span>=</span><span class="string">"java"</span><span>></span><span class="keyword">package</span><span> lab.sodino.sliding; </span></span></li><li class=""><span> </span></li><li class="alt"><span><span class="keyword">import</span><span> java.util.ArrayList; </span></span></li><li class=""><span> </span></li><li class="alt"><span><span class="keyword">import</span><span> android.content.Context; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.content.res.TypedArray; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.graphics.Canvas; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.graphics.Rect; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.util.AttributeSet; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.view.MotionEvent; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.view.View; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.view.ViewConfiguration; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.view.ViewGroup; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.widget.Scroller; </span></span></li><li class="alt"><span> </span></li><li class=""><span><span class="comment">/**</span> </span></li><li class="alt"><span><span class="comment"> * @author Sodino E-mail:sodinoopen@hotmail.com</span> </span></li><li class=""><span><span class="comment"> * @version Time:2012-1-18 下午02:55:59</span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li class=""><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> SlidingContainer </span><span class="keyword">extends</span><span> ViewGroup { </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> INVALID_SCREEN = -</span><span class="number">1</span><span>; </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> SCROLL_DURATION = </span><span class="number">500</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> SPEC_UNDEFINED = ViewGroup.LayoutParams.FILL_PARENT; </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> SNAP_VELOCITY = </span><span class="number">500</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> STATE_STATIC = </span><span class="number">0</span><span>; </span></span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> STATE_SCROLLING = </span><span class="number">1</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">int</span><span> pageWidth; </span></span></li><li class=""><span> <span class="comment">/**</span> </span></li><li class="alt"><span><span class="comment"> * 标识是否是第一次布局。<br/></span> </span></li><li class=""><span><span class="comment"> * 第一次布局需要将第一页调居中显示在屏幕上。<br/></span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">boolean</span><span> isFirstLayout; </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">int</span><span> currentPage, nextPage; </span></span></li><li class=""><span> <span class="keyword">private</span><span> Scroller scroller; </span></span></li><li class="alt"><span> <span class="comment">/** 手指滑动过程中可理解为拖动的最小长度。 */</span><span> </span></span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">int</span><span> distanceSlop; </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">int</span><span> state = STATE_STATIC; </span></span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">float</span><span> lastMotionX; </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> OnSlidingListener slidingListener; </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> SlidingContainer(Context context, AttributeSet attrs, </span><span class="keyword">int</span><span> defStyle) { </span></span></li><li class=""><span> <span class="keyword">super</span><span>(context, attrs, defStyle); </span></span></li><li class="alt"><span> LogOut.out(<span class="keyword">this</span><span>, </span><span class="string">"SlidingContainer() 3"</span><span>); </span></span></li><li class=""><span> initialization(context, attrs); </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> SlidingContainer(Context context, AttributeSet attrs) { </span></span></li><li class=""><span> <span class="keyword">super</span><span>(context, attrs); </span></span></li><li class="alt"><span> LogOut.out(<span class="keyword">this</span><span>, </span><span class="string">"SlidingContainer() 2"</span><span>); </span></span></li><li class=""><span> initialization(context, attrs); </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> SlidingContainer(Context context) { </span></span></li><li class=""><span> <span class="keyword">super</span><span>(context); </span></span></li><li class="alt"><span> LogOut.out(<span class="keyword">this</span><span>, </span><span class="string">"SlidingContainer() 1"</span><span>); </span></span></li><li class=""><span> initialization(context, <span class="keyword">null</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">void</span><span> initialization(Context context, AttributeSet attrs) { </span></span></li><li class=""><span> <span class="keyword">if</span><span> (attrs != </span><span class="keyword">null</span><span>) { </span></span></li><li class="alt"><span> TypedArray typedArr = context.obtainStyledAttributes(attrs, R.styleable.sliding_SlidingContainer); </span></li><li class=""><span> pageWidth = typedArr.getDimensionPixelSize(R.styleable.sliding_SlidingContainer_pageWidth, SPEC_UNDEFINED); </span></li><li class="alt"><span> typedArr.recycle(); </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> state = STATE_STATIC; </span></li><li class="alt"><span> isFirstLayout = <span class="keyword">true</span><span>; </span></span></li><li class=""><span> currentPage = <span class="number">0</span><span>; </span></span></li><li class="alt"><span> nextPage = INVALID_SCREEN; </span></li><li class=""><span> </span></li><li class="alt"><span> scroller = <span class="keyword">new</span><span> Scroller(context); </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">final</span><span> ViewConfiguration configuration = ViewConfiguration.get(context); </span></span></li><li class=""><span> distanceSlop = configuration.getScaledTouchSlop(); </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getCurrentPage() { </span></span></li><li class=""><span> <span class="keyword">return</span><span> currentPage; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getScrollXByPage(</span><span class="keyword">int</span><span> page) { </span></span></li><li class=""><span> <span class="keyword">return</span><span> (page * pageWidth) - getPagePadding(); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getPagePadding() { </span></span></li><li class=""><span> <span class="keyword">return</span><span> (getMeasuredWidth() - pageWidth) >> </span><span class="number">1</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getPageWidth() { </span></span></li><li class=""><span> <span class="keyword">return</span><span> pageWidth; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> scroll2page(</span><span class="keyword">int</span><span> page) { </span></span></li><li class=""><span> <span class="keyword">if</span><span> (page < </span><span class="number">0</span><span>) { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">false</span><span>; </span></span></li><li class=""><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (page >= getChildCount()) { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">false</span><span>; </span></span></li><li class=""><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (scroller.isFinished() == </span><span class="keyword">false</span><span>) { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">false</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> enableChildrenCache(<span class="keyword">true</span><span>); </span></span></li><li class=""><span> <span class="keyword">boolean</span><span> changingPage = (page != currentPage); </span></span></li><li class="alt"><span> nextPage = page; </span></li><li class=""><span> </span></li><li class="alt"><span> View focusedChild = getFocusedChild(); </span></li><li class=""><span> <span class="keyword">if</span><span> (changingPage && focusedChild != </span><span class="keyword">null</span><span> && focusedChild == getChildAt(currentPage)) { </span></span></li><li class="alt"><span> focusedChild.clearFocus(); </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> nowX = getScrollX(); </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> newX = getScrollXByPage(nextPage); </span></span></li><li class=""><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> move = newX - nowX; </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> absMove = Math.abs(move); </span></span></li><li class=""><span> <span class="keyword">int</span><span> duration = SCROLL_DURATION; </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (absMove < pageWidth) { </span></span></li><li class=""><span> duration = SCROLL_DURATION * absMove / pageWidth; </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">// 启动左右切屏动画</span><span> </span></span></li><li class="alt"><span> scroller.startScroll(nowX, <span class="number">0</span><span>, move, </span><span class="number">0</span><span>, duration); </span></span></li><li class=""><span> invalidate(); </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">true</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">void</span><span> checkScrolling(</span><span class="keyword">float</span><span> x) { </span></span></li><li class="alt"><span> <span class="keyword">float</span><span> diff = Math.abs(x - lastMotionX); </span></span></li><li class=""><span> <span class="keyword">if</span><span> (diff > distanceSlop) { </span></span></li><li class="alt"><span> state = STATE_SCROLLING; </span></li><li class=""><span> enableChildrenCache(<span class="keyword">true</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="comment">/**</span> </span></li><li class="alt"><span><span class="comment"> * 开始滑动时设置允许使用缓存。<br/></span> </span></li><li class=""><span><span class="comment"> * 结束滑动时设置取消缓存。<br/></span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> enableChildrenCache(</span><span class="keyword">boolean</span><span> enable) { </span></span></li><li class="alt"><span> setChildrenDrawingCacheEnabled(enable); </span></li><li class=""><span> setChildrenDrawnWithCacheEnabled(enable); </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="comment">/** 在正式显示之前设置才有效。 */</span><span> </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> setPageWidth(</span><span class="keyword">int</span><span> width) { </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (isFirstLayout) { </span></span></li><li class=""><span> pageWidth = width; </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">true</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">false</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> setOnSlidingListener(OnSlidingListener listener) { </span></span></li><li class="alt"><span> slidingListener = listener; </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> onMeasure(</span><span class="keyword">int</span><span> widthMeasureSpec, </span><span class="keyword">int</span><span> heightMeasureSpec) { </span></span></li><li class="alt"><span> LogOut.out(<span class="keyword">this</span><span>, </span><span class="string">"onMeasure()"</span><span>); </span></span></li><li class=""><span> <span class="keyword">super</span><span>.onMeasure(widthMeasureSpec, heightMeasureSpec); </span></span></li><li class="alt"><span> </span></li><li class=""><span> pageWidth = (pageWidth == SPEC_UNDEFINED) ? getMeasuredWidth() : pageWidth; </span></li><li class="alt"><span> pageWidth = Math.min(Math.max(<span class="number">0</span><span>, pageWidth), getMeasuredWidth()); </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> count = getChildCount(); </span></span></li><li class=""><span> <span class="keyword">for</span><span> (</span><span class="keyword">int</span><span> i = </span><span class="number">0</span><span>; i < count; i++) { </span></span></li><li class="alt"><span> <span class="keyword">int</span><span> childWidthSpec = MeasureSpec.makeMeasureSpec(pageWidth, MeasureSpec.EXACTLY); </span></span></li><li class=""><span> View view = getChildAt(i); </span></li><li class="alt"><span> view.measure(childWidthSpec, heightMeasureSpec); </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="annotation">@Override</span><span> </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> onLayout(</span><span class="keyword">boolean</span><span> changing, </span><span class="keyword">int</span><span> left, </span><span class="keyword">int</span><span> top, </span><span class="keyword">int</span><span> right, </span><span class="keyword">int</span><span> bottom) { </span></span></li><li class="alt"><span> LogOut.out(<span class="keyword">this</span><span>, </span><span class="string">"onLayout"</span><span>); </span></span></li><li class=""><span> <span class="keyword">int</span><span> childLeft = </span><span class="number">0</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> count = getChildCount(); </span></span></li><li class=""><span> <span class="keyword">for</span><span> (</span><span class="keyword">int</span><span> i = </span><span class="number">0</span><span>; i < count; i++) { </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> View view = getChildAt(i); </span></span></li><li class=""><span> <span class="keyword">if</span><span> (view.getVisibility() != View.GONE) { </span></span></li><li class="alt"><span> <span class="keyword">int</span><span> childWidth = view.getMeasuredWidth(); </span></span></li><li class=""><span> view.layout(childLeft, <span class="number">0</span><span>, childLeft + childWidth, view.getMeasuredHeight()); </span></span></li><li class="alt"><span> childLeft += childWidth; </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">if</span><span> (isFirstLayout) { </span></span></li><li class=""><span> scrollTo(getScrollXByPage(currentPage), <span class="number">0</span><span>); </span></span></li><li class="alt"><span> isFirstLayout = <span class="keyword">false</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> onInterceptTouchEvent(MotionEvent event) { </span></span></li><li class=""><span> LogOut.out(<span class="keyword">this</span><span>, </span><span class="string">"onInterceptTouchEvent action="</span><span> + event.getAction()); </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> action = event.getAction(); </span></span></li><li class=""><span> <span class="keyword">if</span><span> (action == MotionEvent.ACTION_MOVE && state != STATE_STATIC) { </span></span></li><li class="alt"><span> <span class="comment">// MOVE及非静止情况下,返回TRUE阻止将此事件传递给子组件,</span><span> </span></span></li><li class=""><span> <span class="comment">// 而是执行onTouchEvent()来实现滑动</span><span> </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">true</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">float</span><span> x = event.getX(); </span></span></li><li class=""><span> <span class="keyword">switch</span><span> (action) { </span></span></li><li class="alt"><span> <span class="keyword">case</span><span> MotionEvent.ACTION_DOWN: </span></span></li><li class=""><span> lastMotionX = x; </span></li><li class="alt"><span> <span class="comment">// 点击按钮时,此处设置状态为静止。</span><span> </span></span></li><li class=""><span> state = scroller.isFinished() ? STATE_STATIC : STATE_SCROLLING; </span></li><li class="alt"><span> <span class="keyword">break</span><span>; </span></span></li><li class=""><span> <span class="keyword">case</span><span> MotionEvent.ACTION_MOVE: </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (state == STATE_STATIC) { </span></span></li><li class=""><span> <span class="comment">// 由于已静止,在点击按钮后进行拖拉,则根据拖拉位移大小决定是否需要改变状态进而进一步拦截此事件。</span><span> </span></span></li><li class="alt"><span> checkScrolling(x); </span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">break</span><span>; </span></span></li><li class=""><span> <span class="keyword">case</span><span> MotionEvent.ACTION_UP: </span></span></li><li class="alt"><span> <span class="keyword">case</span><span> MotionEvent.ACTION_CANCEL: </span></span></li><li class=""><span> enableChildrenCache(<span class="keyword">false</span><span>); </span></span></li><li class="alt"><span> state = STATE_STATIC; </span></li><li class=""><span> <span class="keyword">break</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">// 非静止状态,将此事件交由onTouchEvent()处理。</span><span> </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> state != STATE_STATIC; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> onTouchEvent(MotionEvent event) { </span></span></li><li class="alt"><span> LogOut.out(<span class="keyword">this</span><span>, </span><span class="string">"onTouchEvent"</span><span>); </span></span></li><li class=""><span> <span class="keyword">super</span><span>.onTouchEvent(event); </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> action = event.getAction(); </span></span></li><li class=""><span> <span class="keyword">final</span><span> </span><span class="keyword">float</span><span> x = event.getX(); </span></span></li><li class="alt"><span> <span class="keyword">switch</span><span> (action) { </span></span></li><li class=""><span> <span class="keyword">case</span><span> MotionEvent.ACTION_DOWN: </span></span></li><li class="alt"><span> lastMotionX = x; </span></li><li class=""><span> <span class="keyword">if</span><span> (scroller.isFinished() == </span><span class="keyword">false</span><span>) { </span></span></li><li class="alt"><span> scroller.abortAnimation(); </span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">break</span><span>; </span></span></li><li class=""><span> <span class="keyword">case</span><span> MotionEvent.ACTION_MOVE: </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (state == STATE_STATIC) { </span></span></li><li class=""><span> checkScrolling(x); </span></li><li class="alt"><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (state == STATE_SCROLLING) { </span></span></li><li class=""><span> <span class="keyword">int</span><span> moveX = (</span><span class="keyword">int</span><span>) (lastMotionX - x); </span></span></li><li class="alt"><span> lastMotionX = x; </span></li><li class=""><span> <span class="keyword">if</span><span> (getScrollX() < </span><span class="number">0</span><span> || getScrollX() > getChildAt(getChildCount() - </span><span class="number">1</span><span>).getLeft()) { </span></span></li><li class="alt"><span> <span class="comment">// 对于越界的拖拉,则将位移减半。</span><span> </span></span></li><li class=""><span> moveX = moveX >> <span class="number">1</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> scrollBy(moveX, <span class="number">0</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">break</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">case</span><span> MotionEvent.ACTION_UP: </span></span></li><li class=""><span> <span class="keyword">case</span><span> MotionEvent.ACTION_CANCEL: </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (state == STATE_SCROLLING) { </span></span></li><li class=""><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> startX = getScrollXByPage(currentPage); </span></span></li><li class="alt"><span> <span class="comment">// 默认选择回到手指滑动之前的当前页</span><span> </span></span></li><li class=""><span> <span class="keyword">int</span><span> whichPage = currentPage; </span></span></li><li class="alt"><span> <span class="keyword">int</span><span> xSpace = getWidth() / </span><span class="number">8</span><span>; </span></span></li><li class=""><span> <span class="keyword">if</span><span> (getScrollX() < startX - xSpace) { </span></span></li><li class="alt"><span> whichPage = Math.max(<span class="number">0</span><span>, whichPage - </span><span class="number">1</span><span>); </span></span></li><li class=""><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (getScrollX() > startX + xSpace) { </span></span></li><li class="alt"><span> whichPage = Math.min(getChildCount() - <span class="number">1</span><span>, whichPage + </span><span class="number">1</span><span>); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> scroll2page(whichPage); </span></li><li class=""><span> } </span></li><li class="alt"><span> state = STATE_STATIC; </span></li><li class=""><span> <span class="keyword">break</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="keyword">true</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="comment">/** 让拖拉、动画过程中界面过渡顺滑。 */</span><span> </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> dispatchDraw(Canvas canvas) { </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">long</span><span> drawingTime = getDrawingTime(); </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> count = getChildCount(); </span></span></li><li class=""><span> <span class="keyword">for</span><span> (</span><span class="keyword">int</span><span> i = </span><span class="number">0</span><span>; i < count; i++) { </span></span></li><li class="alt"><span> drawChild(canvas, getChildAt(i), drawingTime); </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">if</span><span> (slidingListener != </span><span class="keyword">null</span><span>) { </span></span></li><li class="alt"><span> <span class="keyword">int</span><span> adjustedScrollX = getScrollX() + getPagePadding(); </span></span></li><li class=""><span> slidingListener.onSliding(adjustedScrollX); </span></li><li class="alt"><span> <span class="keyword">if</span><span> (adjustedScrollX % pageWidth == </span><span class="number">0</span><span>) { </span></span></li><li class=""><span> slidingListener.onSlidingEnd(adjustedScrollX / pageWidth, adjustedScrollX); </span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="comment">/** 与Scroller相匹配,实现动画效果中每一帧的界面更新。 */</span><span> </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> computeScroll() { </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (scroller.computeScrollOffset()) { </span></span></li><li class=""><span> scrollTo(scroller.getCurrX(), scroller.getCurrY()); </span></li><li class="alt"><span> postInvalidate(); </span></li><li class=""><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (nextPage != INVALID_SCREEN) { </span></span></li><li class="alt"><span> currentPage = nextPage; </span></li><li class=""><span> nextPage = INVALID_SCREEN; </span></li><li class="alt"><span> enableChildrenCache(<span class="keyword">false</span><span>); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">interface</span><span> OnSlidingListener { </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> onSliding(</span><span class="keyword">int</span><span> scrollX); </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> onSlidingEnd(</span><span class="keyword">int</span><span> pageIdx, </span><span class="keyword">int</span><span> scrollX); </span></span></li><li class=""><span> } </span></li><li class="alt"><span>}</pre><br> </span></li><li class=""><span><br> </span></li><li class="alt"><span>SlidingIndicator.java<br> </span></li><li class=""><span><p></p> </span></li><li class="alt"><span><pre name=<span class="string">"code"</span><span> </span><span class="keyword">class</span><span>=</span><span class="string">"java"</span><span>></span><span class="keyword">package</span><span> lab.sodino.sliding; </span></span></li><li class=""><span> </span></li><li class="alt"><span><span class="keyword">import</span><span> android.content.Context; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.content.res.TypedArray; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.graphics.Canvas; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.graphics.Paint; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.graphics.RectF; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.util.AttributeSet; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.view.View; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.view.animation.AlphaAnimation; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.view.animation.Animation; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.view.animation.AnimationUtils; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.view.animation.LinearInterpolator; </span></span></li><li class=""><span> </span></li><li class="alt"><span><span class="comment">/**</span> </span></li><li class=""><span><span class="comment"> * @author Sodino E-mail:sodinoopen@hotmail.com</span> </span></li><li class="alt"><span><span class="comment"> * @version Time:2012-1-18 下午03:31:08</span> </span></li><li class=""><span><span class="comment"> */</span><span> </span></span></li><li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> SlidingIndicator </span><span class="keyword">extends</span><span> View { </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> BAR_COLOR = </span><span class="number">0xaa777777</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> HIGHLIGHT_COLOR = </span><span class="number">0xaa999999</span><span>; </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> FADE_DELAY = </span><span class="number">2000</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> FADE_DURATION = </span><span class="number">500</span><span>; </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">int</span><span> amount, currentPage, position; </span></span></li><li class=""><span> <span class="keyword">private</span><span> Paint barPaint, highlightPaint; </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">int</span><span> fadeDelay, fadeDuration; </span></span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">float</span><span> ovalRadius; </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> Animation animFadeout; </span></span></li><li class=""><span> <span class="comment">/** RectF比Rect是精度上更精确。 */</span><span> </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> RectF rectFBody, rectFIndicator; </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> SlidingIndicator(Context context, AttributeSet attrs, </span><span class="keyword">int</span><span> defStyle) { </span></span></li><li class=""><span> <span class="keyword">super</span><span>(context, attrs, defStyle); </span></span></li><li class="alt"><span> <span class="comment">// 预设值。</span><span> </span></span></li><li class=""><span> <span class="keyword">int</span><span> barColor = BAR_COLOR, highlightColor = HIGHLIGHT_COLOR; </span></span></li><li class="alt"><span> fadeDelay = FADE_DELAY; </span></li><li class=""><span> fadeDuration = FADE_DURATION; </span></li><li class="alt"><span> <span class="keyword">if</span><span> (attrs != </span><span class="keyword">null</span><span>) { </span></span></li><li class=""><span> TypedArray typedArr = context.obtainStyledAttributes(attrs, R.styleable.sliding_SlidingIndicator); </span></li><li class="alt"><span> barColor = typedArr.getColor(R.styleable.sliding_SlidingIndicator_barColor, BAR_COLOR); </span></li><li class=""><span> highlightColor = typedArr.getColor(R.styleable.sliding_SlidingIndicator_highlightColor, HIGHLIGHT_COLOR); </span></li><li class="alt"><span> fadeDelay = typedArr.getInteger(R.styleable.sliding_SlidingIndicator_fadeDelay, FADE_DELAY); </span></li><li class=""><span> fadeDuration = typedArr.getInteger(R.styleable.sliding_SlidingIndicator_fadeDuration, FADE_DURATION); </span></li><li class="alt"><span> ovalRadius = typedArr.getDimension(R.styleable.sliding_SlidingIndicator_roundRectRadius, 0f); </span></li><li class=""><span> typedArr.recycle(); </span></li><li class="alt"><span> } </span></li><li class=""><span> initialization(barColor, highlightColor, fadeDuration); </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> SlidingIndicator(Context context, AttributeSet attrs) { </span></span></li><li class=""><span> <span class="keyword">this</span><span>(context, attrs, </span><span class="number">0</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> SlidingIndicator(Context context) { </span></span></li><li class=""><span> <span class="keyword">super</span><span>(context); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">void</span><span> initialization(</span><span class="keyword">int</span><span> barColor, </span><span class="keyword">int</span><span> highlightColor, </span><span class="keyword">int</span><span> fadeDuration) { </span></span></li><li class=""><span> barPaint = <span class="keyword">new</span><span> Paint(); </span></span></li><li class="alt"><span> barPaint.setColor(barColor); </span></li><li class=""><span> </span></li><li class="alt"><span> highlightPaint = <span class="keyword">new</span><span> Paint(); </span></span></li><li class=""><span> highlightPaint.setColor(highlightColor); </span></li><li class="alt"><span> </span></li><li class=""><span> animFadeout = <span class="keyword">new</span><span> AlphaAnimation(1f, 0f); </span></span></li><li class="alt"><span> animFadeout.setDuration(fadeDuration); </span></li><li class=""><span> animFadeout.setRepeatCount(<span class="number">0</span><span>); </span></span></li><li class="alt"><span> animFadeout.setInterpolator(<span class="keyword">new</span><span> LinearInterpolator()); </span></span></li><li class=""><span> <span class="comment">// 设置动画结束后,本组件保持动画结束时的最后状态,即全透明不可见。</span><span> </span></span></li><li class="alt"><span> animFadeout.setFillEnabled(<span class="keyword">true</span><span>); </span></span></li><li class=""><span> animFadeout.setFillAfter(<span class="keyword">true</span><span>); </span></span></li><li class="alt"><span> </span></li><li class=""><span> rectFBody = <span class="keyword">new</span><span> RectF(); </span></span></li><li class="alt"><span> rectFIndicator = <span class="keyword">new</span><span> RectF(); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> setPageAmount(</span><span class="keyword">int</span><span> num) { </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (num < </span><span class="number">0</span><span>) { </span></span></li><li class=""><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> IllegalArgumentException(</span><span class="string">"num must be positive."</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> amount = num; </span></li><li class="alt"><span> invalidate(); </span></li><li class=""><span> fadeOut(); </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">void</span><span> fadeOut() { </span></span></li><li class=""><span> <span class="keyword">if</span><span> (fadeDuration > </span><span class="number">0</span><span>) { </span></span></li><li class="alt"><span> clearAnimation(); </span></li><li class=""><span> <span class="comment">// 设置动画的延时时间,此时间段内正好指示当前页位置。</span><span> </span></span></li><li class="alt"><span> animFadeout.setStartTime(AnimationUtils.currentAnimationTimeMillis() + fadeDelay); </span></li><li class=""><span> setAnimation(animFadeout); </span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getCurrentPage() { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> currentPage; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> setCurrentPage(</span><span class="keyword">int</span><span> idx) { </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (currentPage < </span><span class="number">0</span><span> || currentPage >= amount) { </span></span></li><li class=""><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> IllegalArgumentException(</span><span class="string">"currentPage parameter out of bounds"</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">if</span><span> (</span><span class="keyword">this</span><span>.currentPage != idx) { </span></span></li><li class="alt"><span> <span class="keyword">this</span><span>.currentPage = idx; </span></span></li><li class=""><span> <span class="keyword">this</span><span>.position = currentPage * getPageWidth(); </span></span></li><li class="alt"><span> invalidate(); </span></li><li class=""><span> fadeOut(); </span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> setPosition(</span><span class="keyword">int</span><span> position) { </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (</span><span class="keyword">this</span><span>.position != position) { </span></span></li><li class=""><span> <span class="keyword">this</span><span>.position = position; </span></span></li><li class="alt"><span> invalidate(); </span></li><li class=""><span> fadeOut(); </span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getPageWidth() { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> getWidth() / amount; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> onDraw(Canvas canvas) { </span></span></li><li class="alt"><span> rectFBody.set(<span class="number">0</span><span>, </span><span class="number">0</span><span>, getWidth(), getHeight()); </span></span></li><li class=""><span> canvas.drawRoundRect(rectFBody, ovalRadius, ovalRadius, barPaint); </span></li><li class="alt"><span> rectFIndicator.set(position, <span class="number">0</span><span>, position + getPageWidth(), getHeight()); </span></span></li><li class=""><span> canvas.drawRoundRect(rectFIndicator, ovalRadius, ovalRadius, highlightPaint); </span></li><li class="alt"><span> } </span></li><li class=""><span>}</pre><br> </span></li><li class="alt"><span>末尾,自己推荐另一个左右滑屏实现方法:ViewPager<br> </span></li><li class=""><span>http:<span class="comment">//my.oschina.net/kzhou/blog/29157<br></span><span> </span></span></li><li class="alt"><span><pre></pre> </span></li><li class=""><span><pre></pre> </span></li></ol></div><pre name="code" class="java" style="background-color: rgb(255, 255, 255); display: none;"><pre></pre>
<p></p>
<p></p>
<p>SlidingContainer.java</p>
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a><div style="position: absolute; left: 0px; top: 0px; 0px; height: 0px; z-index: 99;"><embed id="ZeroClipboardMovie_5" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="0" height="0" name="ZeroClipboardMovie_5" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=5&width=0&height=0" wmode="transparent"></div></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">package</span><span> lab.sodino.sliding; </span></span></li><li class=""><span> </span></li><li class="alt"><span><span class="keyword">import</span><span> java.util.ArrayList; </span></span></li><li class=""><span> </span></li><li class="alt"><span><span class="keyword">import</span><span> android.content.Context; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.content.res.TypedArray; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.graphics.Canvas; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.graphics.Rect; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.util.AttributeSet; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.view.MotionEvent; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.view.View; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.view.ViewConfiguration; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.view.ViewGroup; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.widget.Scroller; </span></span></li><li class="alt"><span> </span></li><li class=""><span><span class="comment">/**</span> </span></li><li class="alt"><span><span class="comment"> * @author Sodino E-mail:sodinoopen@hotmail.com</span> </span></li><li class=""><span><span class="comment"> * @version Time:2012-1-18 下午02:55:59</span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li class=""><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> SlidingContainer </span><span class="keyword">extends</span><span> ViewGroup { </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> INVALID_SCREEN = -</span><span class="number">1</span><span>; </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> SCROLL_DURATION = </span><span class="number">500</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> SPEC_UNDEFINED = ViewGroup.LayoutParams.FILL_PARENT; </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> SNAP_VELOCITY = </span><span class="number">500</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> STATE_STATIC = </span><span class="number">0</span><span>; </span></span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> STATE_SCROLLING = </span><span class="number">1</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">int</span><span> pageWidth; </span></span></li><li class=""><span> <span class="comment">/**</span> </span></li><li class="alt"><span><span class="comment"> * 标识是否是第一次布局。<br/></span> </span></li><li class=""><span><span class="comment"> * 第一次布局需要将第一页调居中显示在屏幕上。<br/></span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">boolean</span><span> isFirstLayout; </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">int</span><span> currentPage, nextPage; </span></span></li><li class=""><span> <span class="keyword">private</span><span> Scroller scroller; </span></span></li><li class="alt"><span> <span class="comment">/** 手指滑动过程中可理解为拖动的最小长度。 */</span><span> </span></span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">int</span><span> distanceSlop; </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">int</span><span> state = STATE_STATIC; </span></span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">float</span><span> lastMotionX; </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> OnSlidingListener slidingListener; </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> SlidingContainer(Context context, AttributeSet attrs, </span><span class="keyword">int</span><span> defStyle) { </span></span></li><li class=""><span> <span class="keyword">super</span><span>(context, attrs, defStyle); </span></span></li><li class="alt"><span> LogOut.out(<span class="keyword">this</span><span>, </span><span class="string">"SlidingContainer() 3"</span><span>); </span></span></li><li class=""><span> initialization(context, attrs); </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> SlidingContainer(Context context, AttributeSet attrs) { </span></span></li><li class=""><span> <span class="keyword">super</span><span>(context, attrs); </span></span></li><li class="alt"><span> LogOut.out(<span class="keyword">this</span><span>, </span><span class="string">"SlidingContainer() 2"</span><span>); </span></span></li><li class=""><span> initialization(context, attrs); </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> SlidingContainer(Context context) { </span></span></li><li class=""><span> <span class="keyword">super</span><span>(context); </span></span></li><li class="alt"><span> LogOut.out(<span class="keyword">this</span><span>, </span><span class="string">"SlidingContainer() 1"</span><span>); </span></span></li><li class=""><span> initialization(context, <span class="keyword">null</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">void</span><span> initialization(Context context, AttributeSet attrs) { </span></span></li><li class=""><span> <span class="keyword">if</span><span> (attrs != </span><span class="keyword">null</span><span>) { </span></span></li><li class="alt"><span> TypedArray typedArr = context.obtainStyledAttributes(attrs, R.styleable.sliding_SlidingContainer); </span></li><li class=""><span> pageWidth = typedArr.getDimensionPixelSize(R.styleable.sliding_SlidingContainer_pageWidth, SPEC_UNDEFINED); </span></li><li class="alt"><span> typedArr.recycle(); </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> state = STATE_STATIC; </span></li><li class="alt"><span> isFirstLayout = <span class="keyword">true</span><span>; </span></span></li><li class=""><span> currentPage = <span class="number">0</span><span>; </span></span></li><li class="alt"><span> nextPage = INVALID_SCREEN; </span></li><li class=""><span> </span></li><li class="alt"><span> scroller = <span class="keyword">new</span><span> Scroller(context); </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">final</span><span> ViewConfiguration configuration = ViewConfiguration.get(context); </span></span></li><li class=""><span> distanceSlop = configuration.getScaledTouchSlop(); </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getCurrentPage() { </span></span></li><li class=""><span> <span class="keyword">return</span><span> currentPage; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getScrollXByPage(</span><span class="keyword">int</span><span> page) { </span></span></li><li class=""><span> <span class="keyword">return</span><span> (page * pageWidth) - getPagePadding(); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getPagePadding() { </span></span></li><li class=""><span> <span class="keyword">return</span><span> (getMeasuredWidth() - pageWidth) >> </span><span class="number">1</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getPageWidth() { </span></span></li><li class=""><span> <span class="keyword">return</span><span> pageWidth; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> scroll2page(</span><span class="keyword">int</span><span> page) { </span></span></li><li class=""><span> <span class="keyword">if</span><span> (page < </span><span class="number">0</span><span>) { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">false</span><span>; </span></span></li><li class=""><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (page >= getChildCount()) { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">false</span><span>; </span></span></li><li class=""><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (scroller.isFinished() == </span><span class="keyword">false</span><span>) { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">false</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> enableChildrenCache(<span class="keyword">true</span><span>); </span></span></li><li class=""><span> <span class="keyword">boolean</span><span> changingPage = (page != currentPage); </span></span></li><li class="alt"><span> nextPage = page; </span></li><li class=""><span> </span></li><li class="alt"><span> View focusedChild = getFocusedChild(); </span></li><li class=""><span> <span class="keyword">if</span><span> (changingPage && focusedChild != </span><span class="keyword">null</span><span> && focusedChild == getChildAt(currentPage)) { </span></span></li><li class="alt"><span> focusedChild.clearFocus(); </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> nowX = getScrollX(); </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> newX = getScrollXByPage(nextPage); </span></span></li><li class=""><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> move = newX - nowX; </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> absMove = Math.abs(move); </span></span></li><li class=""><span> <span class="keyword">int</span><span> duration = SCROLL_DURATION; </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (absMove < pageWidth) { </span></span></li><li class=""><span> duration = SCROLL_DURATION * absMove / pageWidth; </span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">// 启动左右切屏动画</span><span> </span></span></li><li class="alt"><span> scroller.startScroll(nowX, <span class="number">0</span><span>, move, </span><span class="number">0</span><span>, duration); </span></span></li><li class=""><span> invalidate(); </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">true</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">void</span><span> checkScrolling(</span><span class="keyword">float</span><span> x) { </span></span></li><li class="alt"><span> <span class="keyword">float</span><span> diff = Math.abs(x - lastMotionX); </span></span></li><li class=""><span> <span class="keyword">if</span><span> (diff > distanceSlop) { </span></span></li><li class="alt"><span> state = STATE_SCROLLING; </span></li><li class=""><span> enableChildrenCache(<span class="keyword">true</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="comment">/**</span> </span></li><li class="alt"><span><span class="comment"> * 开始滑动时设置允许使用缓存。<br/></span> </span></li><li class=""><span><span class="comment"> * 结束滑动时设置取消缓存。<br/></span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> enableChildrenCache(</span><span class="keyword">boolean</span><span> enable) { </span></span></li><li class="alt"><span> setChildrenDrawingCacheEnabled(enable); </span></li><li class=""><span> setChildrenDrawnWithCacheEnabled(enable); </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="comment">/** 在正式显示之前设置才有效。 */</span><span> </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> setPageWidth(</span><span class="keyword">int</span><span> width) { </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (isFirstLayout) { </span></span></li><li class=""><span> pageWidth = width; </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">true</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">false</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> setOnSlidingListener(OnSlidingListener listener) { </span></span></li><li class="alt"><span> slidingListener = listener; </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> onMeasure(</span><span class="keyword">int</span><span> widthMeasureSpec, </span><span class="keyword">int</span><span> heightMeasureSpec) { </span></span></li><li class="alt"><span> LogOut.out(<span class="keyword">this</span><span>, </span><span class="string">"onMeasure()"</span><span>); </span></span></li><li class=""><span> <span class="keyword">super</span><span>.onMeasure(widthMeasureSpec, heightMeasureSpec); </span></span></li><li class="alt"><span> </span></li><li class=""><span> pageWidth = (pageWidth == SPEC_UNDEFINED) ? getMeasuredWidth() : pageWidth; </span></li><li class="alt"><span> pageWidth = Math.min(Math.max(<span class="number">0</span><span>, pageWidth), getMeasuredWidth()); </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> count = getChildCount(); </span></span></li><li class=""><span> <span class="keyword">for</span><span> (</span><span class="keyword">int</span><span> i = </span><span class="number">0</span><span>; i < count; i++) { </span></span></li><li class="alt"><span> <span class="keyword">int</span><span> childWidthSpec = MeasureSpec.makeMeasureSpec(pageWidth, MeasureSpec.EXACTLY); </span></span></li><li class=""><span> View view = getChildAt(i); </span></li><li class="alt"><span> view.measure(childWidthSpec, heightMeasureSpec); </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="annotation">@Override</span><span> </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> onLayout(</span><span class="keyword">boolean</span><span> changing, </span><span class="keyword">int</span><span> left, </span><span class="keyword">int</span><span> top, </span><span class="keyword">int</span><span> right, </span><span class="keyword">int</span><span> bottom) { </span></span></li><li class="alt"><span> LogOut.out(<span class="keyword">this</span><span>, </span><span class="string">"onLayout"</span><span>); </span></span></li><li class=""><span> <span class="keyword">int</span><span> childLeft = </span><span class="number">0</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> count = getChildCount(); </span></span></li><li class=""><span> <span class="keyword">for</span><span> (</span><span class="keyword">int</span><span> i = </span><span class="number">0</span><span>; i < count; i++) { </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> View view = getChildAt(i); </span></span></li><li class=""><span> <span class="keyword">if</span><span> (view.getVisibility() != View.GONE) { </span></span></li><li class="alt"><span> <span class="keyword">int</span><span> childWidth = view.getMeasuredWidth(); </span></span></li><li class=""><span> view.layout(childLeft, <span class="number">0</span><span>, childLeft + childWidth, view.getMeasuredHeight()); </span></span></li><li class="alt"><span> childLeft += childWidth; </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">if</span><span> (isFirstLayout) { </span></span></li><li class=""><span> scrollTo(getScrollXByPage(currentPage), <span class="number">0</span><span>); </span></span></li><li class="alt"><span> isFirstLayout = <span class="keyword">false</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> onInterceptTouchEvent(MotionEvent event) { </span></span></li><li class=""><span> LogOut.out(<span class="keyword">this</span><span>, </span><span class="string">"onInterceptTouchEvent action="</span><span> + event.getAction()); </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> action = event.getAction(); </span></span></li><li class=""><span> <span class="keyword">if</span><span> (action == MotionEvent.ACTION_MOVE && state != STATE_STATIC) { </span></span></li><li class="alt"><span> <span class="comment">// MOVE及非静止情况下,返回TRUE阻止将此事件传递给子组件,</span><span> </span></span></li><li class=""><span> <span class="comment">// 而是执行onTouchEvent()来实现滑动</span><span> </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">true</span><span>; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">float</span><span> x = event.getX(); </span></span></li><li class=""><span> <span class="keyword">switch</span><span> (action) { </span></span></li><li class="alt"><span> <span class="keyword">case</span><span> MotionEvent.ACTION_DOWN: </span></span></li><li class=""><span> lastMotionX = x; </span></li><li class="alt"><span> <span class="comment">// 点击按钮时,此处设置状态为静止。</span><span> </span></span></li><li class=""><span> state = scroller.isFinished() ? STATE_STATIC : STATE_SCROLLING; </span></li><li class="alt"><span> <span class="keyword">break</span><span>; </span></span></li><li class=""><span> <span class="keyword">case</span><span> MotionEvent.ACTION_MOVE: </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (state == STATE_STATIC) { </span></span></li><li class=""><span> <span class="comment">// 由于已静止,在点击按钮后进行拖拉,则根据拖拉位移大小决定是否需要改变状态进而进一步拦截此事件。</span><span> </span></span></li><li class="alt"><span> checkScrolling(x); </span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">break</span><span>; </span></span></li><li class=""><span> <span class="keyword">case</span><span> MotionEvent.ACTION_UP: </span></span></li><li class="alt"><span> <span class="keyword">case</span><span> MotionEvent.ACTION_CANCEL: </span></span></li><li class=""><span> enableChildrenCache(<span class="keyword">false</span><span>); </span></span></li><li class="alt"><span> state = STATE_STATIC; </span></li><li class=""><span> <span class="keyword">break</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="comment">// 非静止状态,将此事件交由onTouchEvent()处理。</span><span> </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> state != STATE_STATIC; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> onTouchEvent(MotionEvent event) { </span></span></li><li class="alt"><span> LogOut.out(<span class="keyword">this</span><span>, </span><span class="string">"onTouchEvent"</span><span>); </span></span></li><li class=""><span> <span class="keyword">super</span><span>.onTouchEvent(event); </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> action = event.getAction(); </span></span></li><li class=""><span> <span class="keyword">final</span><span> </span><span class="keyword">float</span><span> x = event.getX(); </span></span></li><li class="alt"><span> <span class="keyword">switch</span><span> (action) { </span></span></li><li class=""><span> <span class="keyword">case</span><span> MotionEvent.ACTION_DOWN: </span></span></li><li class="alt"><span> lastMotionX = x; </span></li><li class=""><span> <span class="keyword">if</span><span> (scroller.isFinished() == </span><span class="keyword">false</span><span>) { </span></span></li><li class="alt"><span> scroller.abortAnimation(); </span></li><li class=""><span> } </span></li><li class="alt"><span> <span class="keyword">break</span><span>; </span></span></li><li class=""><span> <span class="keyword">case</span><span> MotionEvent.ACTION_MOVE: </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (state == STATE_STATIC) { </span></span></li><li class=""><span> checkScrolling(x); </span></li><li class="alt"><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (state == STATE_SCROLLING) { </span></span></li><li class=""><span> <span class="keyword">int</span><span> moveX = (</span><span class="keyword">int</span><span>) (lastMotionX - x); </span></span></li><li class="alt"><span> lastMotionX = x; </span></li><li class=""><span> <span class="keyword">if</span><span> (getScrollX() < </span><span class="number">0</span><span> || getScrollX() > getChildAt(getChildCount() - </span><span class="number">1</span><span>).getLeft()) { </span></span></li><li class="alt"><span> <span class="comment">// 对于越界的拖拉,则将位移减半。</span><span> </span></span></li><li class=""><span> moveX = moveX >> <span class="number">1</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> scrollBy(moveX, <span class="number">0</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">break</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">case</span><span> MotionEvent.ACTION_UP: </span></span></li><li class=""><span> <span class="keyword">case</span><span> MotionEvent.ACTION_CANCEL: </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (state == STATE_SCROLLING) { </span></span></li><li class=""><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> startX = getScrollXByPage(currentPage); </span></span></li><li class="alt"><span> <span class="comment">// 默认选择回到手指滑动之前的当前页</span><span> </span></span></li><li class=""><span> <span class="keyword">int</span><span> whichPage = currentPage; </span></span></li><li class="alt"><span> <span class="keyword">int</span><span> xSpace = getWidth() / </span><span class="number">8</span><span>; </span></span></li><li class=""><span> <span class="keyword">if</span><span> (getScrollX() < startX - xSpace) { </span></span></li><li class="alt"><span> whichPage = Math.max(<span class="number">0</span><span>, whichPage - </span><span class="number">1</span><span>); </span></span></li><li class=""><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (getScrollX() > startX + xSpace) { </span></span></li><li class="alt"><span> whichPage = Math.min(getChildCount() - <span class="number">1</span><span>, whichPage + </span><span class="number">1</span><span>); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> scroll2page(whichPage); </span></li><li class=""><span> } </span></li><li class="alt"><span> state = STATE_STATIC; </span></li><li class=""><span> <span class="keyword">break</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">return</span><span> </span><span class="keyword">true</span><span>; </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="comment">/** 让拖拉、动画过程中界面过渡顺滑。 */</span><span> </span></span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> dispatchDraw(Canvas canvas) { </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">long</span><span> drawingTime = getDrawingTime(); </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> count = getChildCount(); </span></span></li><li class=""><span> <span class="keyword">for</span><span> (</span><span class="keyword">int</span><span> i = </span><span class="number">0</span><span>; i < count; i++) { </span></span></li><li class="alt"><span> drawChild(canvas, getChildAt(i), drawingTime); </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">if</span><span> (slidingListener != </span><span class="keyword">null</span><span>) { </span></span></li><li class="alt"><span> <span class="keyword">int</span><span> adjustedScrollX = getScrollX() + getPagePadding(); </span></span></li><li class=""><span> slidingListener.onSliding(adjustedScrollX); </span></li><li class="alt"><span> <span class="keyword">if</span><span> (adjustedScrollX % pageWidth == </span><span class="number">0</span><span>) { </span></span></li><li class=""><span> slidingListener.onSlidingEnd(adjustedScrollX / pageWidth, adjustedScrollX); </span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="comment">/** 与Scroller相匹配,实现动画效果中每一帧的界面更新。 */</span><span> </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> computeScroll() { </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (scroller.computeScrollOffset()) { </span></span></li><li class=""><span> scrollTo(scroller.getCurrX(), scroller.getCurrY()); </span></li><li class="alt"><span> postInvalidate(); </span></li><li class=""><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (nextPage != INVALID_SCREEN) { </span></span></li><li class="alt"><span> currentPage = nextPage; </span></li><li class=""><span> nextPage = INVALID_SCREEN; </span></li><li class="alt"><span> enableChildrenCache(<span class="keyword">false</span><span>); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">interface</span><span> OnSlidingListener { </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> onSliding(</span><span class="keyword">int</span><span> scrollX); </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> onSlidingEnd(</span><span class="keyword">int</span><span> pageIdx, </span><span class="keyword">int</span><span> scrollX); </span></span></li><li class=""><span> } </span></li><li class="alt"><span>} </span></li></ol></div><pre name="code" class="java" style="display: none;">package lab.sodino.sliding;
import java.util.ArrayList;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.Scroller;
/**
* @author Sodino E-mail:sodinoopen@hotmail.com
* @version Time:2012-1-18 下午02:55:59
*/
public class SlidingContainer extends ViewGroup {
private static final int INVALID_SCREEN = -1;
public static final int SCROLL_DURATION = 500;
public static final int SPEC_UNDEFINED = ViewGroup.LayoutParams.FILL_PARENT;
public static final int SNAP_VELOCITY = 500;
private static final int STATE_STATIC = 0;
private static final int STATE_SCROLLING = 1;
private int pageWidth;
/**
* 标识是否是第一次布局。<br/>
* 第一次布局需要将第一页调居中显示在屏幕上。<br/>
*/
private boolean isFirstLayout;
private int currentPage, nextPage;
private Scroller scroller;
/** 手指滑动过程中可理解为拖动的最小长度。 */
private int distanceSlop;
private int state = STATE_STATIC;
private float lastMotionX;
private OnSlidingListener slidingListener;
public SlidingContainer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LogOut.out(this, "SlidingContainer() 3");
initialization(context, attrs);
}
public SlidingContainer(Context context, AttributeSet attrs) {
super(context, attrs);
LogOut.out(this, "SlidingContainer() 2");
initialization(context, attrs);
}
public SlidingContainer(Context context) {
super(context);
LogOut.out(this, "SlidingContainer() 1");
initialization(context, null);
}
private void initialization(Context context, AttributeSet attrs) {
if (attrs != null) {
TypedArray typedArr = context.obtainStyledAttributes(attrs, R.styleable.sliding_SlidingContainer);
pageWidth = typedArr.getDimensionPixelSize(R.styleable.sliding_SlidingContainer_pageWidth, SPEC_UNDEFINED);
typedArr.recycle();
}
state = STATE_STATIC;
isFirstLayout = true;
currentPage = 0;
nextPage = INVALID_SCREEN;
scroller = new Scroller(context);
final ViewConfiguration configuration = ViewConfiguration.get(context);
distanceSlop = configuration.getScaledTouchSlop();
}
public int getCurrentPage() {
return currentPage;
}
public int getScrollXByPage(int page) {
return (page * pageWidth) - getPagePadding();
}
public int getPagePadding() {
return (getMeasuredWidth() - pageWidth) >> 1;
}
public int getPageWidth() {
return pageWidth;
}
public boolean scroll2page(int page) {
if (page < 0) {
return false;
} else if (page >= getChildCount()) {
return false;
} else if (scroller.isFinished() == false) {
return false;
}
enableChildrenCache(true);
boolean changingPage = (page != currentPage);
nextPage = page;
View focusedChild = getFocusedChild();
if (changingPage && focusedChild != null && focusedChild == getChildAt(currentPage)) {
focusedChild.clearFocus();
}
final int nowX = getScrollX();
final int newX = getScrollXByPage(nextPage);
final int move = newX - nowX;
final int absMove = Math.abs(move);
int duration = SCROLL_DURATION;
if (absMove < pageWidth) {
duration = SCROLL_DURATION * absMove / pageWidth;
}
// 启动左右切屏动画
scroller.startScroll(nowX, 0, move, 0, duration);
invalidate();
return true;
}
private void checkScrolling(float x) {
float diff = Math.abs(x - lastMotionX);
if (diff > distanceSlop) {
state = STATE_SCROLLING;
enableChildrenCache(true);
}
}
/**
* 开始滑动时设置允许使用缓存。<br/>
* 结束滑动时设置取消缓存。<br/>
*/
public void enableChildrenCache(boolean enable) {
setChildrenDrawingCacheEnabled(enable);
setChildrenDrawnWithCacheEnabled(enable);
}
/** 在正式显示之前设置才有效。 */
public boolean setPageWidth(int width) {
if (isFirstLayout) {
pageWidth = width;
return true;
}
return false;
}
public void setOnSlidingListener(OnSlidingListener listener) {
slidingListener = listener;
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
LogOut.out(this, "onMeasure()");
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
pageWidth = (pageWidth == SPEC_UNDEFINED) ? getMeasuredWidth() : pageWidth;
pageWidth = Math.min(Math.max(0, pageWidth), getMeasuredWidth());
final int count = getChildCount();
for (int i = 0; i < count; i++) {
int childWidthSpec = MeasureSpec.makeMeasureSpec(pageWidth, MeasureSpec.EXACTLY);
View view = getChildAt(i);
view.measure(childWidthSpec, heightMeasureSpec);
}
}
@Override
protected void onLayout(boolean changing, int left, int top, int right, int bottom) {
LogOut.out(this, "onLayout");
int childLeft = 0;
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View view = getChildAt(i);
if (view.getVisibility() != View.GONE) {
int childWidth = view.getMeasuredWidth();
view.layout(childLeft, 0, childLeft + childWidth, view.getMeasuredHeight());
childLeft += childWidth;
}
}
if (isFirstLayout) {
scrollTo(getScrollXByPage(currentPage), 0);
isFirstLayout = false;
}
}
public boolean onInterceptTouchEvent(MotionEvent event) {
LogOut.out(this, "onInterceptTouchEvent action=" + event.getAction());
final int action = event.getAction();
if (action == MotionEvent.ACTION_MOVE && state != STATE_STATIC) {
// MOVE及非静止情况下,返回TRUE阻止将此事件传递给子组件,
// 而是执行onTouchEvent()来实现滑动
return true;
}
final float x = event.getX();
switch (action) {
case MotionEvent.ACTION_DOWN:
lastMotionX = x;
// 点击按钮时,此处设置状态为静止。
state = scroller.isFinished() ? STATE_STATIC : STATE_SCROLLING;
break;
case MotionEvent.ACTION_MOVE:
if (state == STATE_STATIC) {
// 由于已静止,在点击按钮后进行拖拉,则根据拖拉位移大小决定是否需要改变状态进而进一步拦截此事件。
checkScrolling(x);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
enableChildrenCache(false);
state = STATE_STATIC;
break;
}
// 非静止状态,将此事件交由onTouchEvent()处理。
return state != STATE_STATIC;
}
public boolean onTouchEvent(MotionEvent event) {
LogOut.out(this, "onTouchEvent");
super.onTouchEvent(event);
final int action = event.getAction();
final float x = event.getX();
switch (action) {
case MotionEvent.ACTION_DOWN:
lastMotionX = x;
if (scroller.isFinished() == false) {
scroller.abortAnimation();
}
break;
case MotionEvent.ACTION_MOVE:
if (state == STATE_STATIC) {
checkScrolling(x);
} else if (state == STATE_SCROLLING) {
int moveX = (int) (lastMotionX - x);
lastMotionX = x;
if (getScrollX() < 0 || getScrollX() > getChildAt(getChildCount() - 1).getLeft()) {
// 对于越界的拖拉,则将位移减半。
moveX = moveX >> 1;
}
scrollBy(moveX, 0);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (state == STATE_SCROLLING) {
final int startX = getScrollXByPage(currentPage);
// 默认选择回到手指滑动之前的当前页
int whichPage = currentPage;
int xSpace = getWidth() / 8;
if (getScrollX() < startX - xSpace) {
whichPage = Math.max(0, whichPage - 1);
} else if (getScrollX() > startX + xSpace) {
whichPage = Math.min(getChildCount() - 1, whichPage + 1);
}
scroll2page(whichPage);
}
state = STATE_STATIC;
break;
}
return true;
}
/** 让拖拉、动画过程中界面过渡顺滑。 */
protected void dispatchDraw(Canvas canvas) {
final long drawingTime = getDrawingTime();
final int count = getChildCount();
for (int i = 0; i < count; i++) {
drawChild(canvas, getChildAt(i), drawingTime);
}
if (slidingListener != null) {
int adjustedScrollX = getScrollX() + getPagePadding();
slidingListener.onSliding(adjustedScrollX);
if (adjustedScrollX % pageWidth == 0) {
slidingListener.onSlidingEnd(adjustedScrollX / pageWidth, adjustedScrollX);
}
}
}
/** 与Scroller相匹配,实现动画效果中每一帧的界面更新。 */
public void computeScroll() {
if (scroller.computeScrollOffset()) {
scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
} else if (nextPage != INVALID_SCREEN) {
currentPage = nextPage;
nextPage = INVALID_SCREEN;
enableChildrenCache(false);
}
}
public static interface OnSlidingListener {
public void onSliding(int scrollX);
public void onSlidingEnd(int pageIdx, int scrollX);
}
}</pre><br>
<br>
SlidingIndicator.java<br>
<p></p>
<div class="dp-highlighter bg_java"><div class="bar"><div class="tools"><b>[java]</b> <a href="#" class="ViewSource" title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;">view plain</a><a href="#" class="CopyToClipboard" title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;">copy</a><a href="#" class="PrintSource" title="print" onclick="dp.sh.Toolbar.Command('PrintSource',this);return false;">print</a><a href="#" class="About" title="?" onclick="dp.sh.Toolbar.Command('About',this);return false;">?</a><div style="position: absolute; left: 0px; top: 0px; 0px; height: 0px; z-index: 99;"><embed id="ZeroClipboardMovie_6" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="0" height="0" name="ZeroClipboardMovie_6" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=6&width=0&height=0" wmode="transparent"></div></div></div><ol start="1" class="dp-j"><li class="alt"><span><span class="keyword">package</span><span> lab.sodino.sliding; </span></span></li><li class=""><span> </span></li><li class="alt"><span><span class="keyword">import</span><span> android.content.Context; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.content.res.TypedArray; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.graphics.Canvas; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.graphics.Paint; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.graphics.RectF; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.util.AttributeSet; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.view.View; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.view.animation.AlphaAnimation; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.view.animation.Animation; </span></span></li><li class=""><span><span class="keyword">import</span><span> android.view.animation.AnimationUtils; </span></span></li><li class="alt"><span><span class="keyword">import</span><span> android.view.animation.LinearInterpolator; </span></span></li><li class=""><span> </span></li><li class="alt"><span><span class="comment">/**</span> </span></li><li class=""><span><span class="comment"> * @author Sodino E-mail:sodinoopen@hotmail.com</span> </span></li><li class="alt"><span><span class="comment"> * @version Time:2012-1-18 下午03:31:08</span> </span></li><li class=""><span><span class="comment"> */</span><span> </span></span></li><li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> SlidingIndicator </span><span class="keyword">extends</span><span> View { </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> BAR_COLOR = </span><span class="number">0xaa777777</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> HIGHLIGHT_COLOR = </span><span class="number">0xaa999999</span><span>; </span></span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> FADE_DELAY = </span><span class="number">2000</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> FADE_DURATION = </span><span class="number">500</span><span>; </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">int</span><span> amount, currentPage, position; </span></span></li><li class=""><span> <span class="keyword">private</span><span> Paint barPaint, highlightPaint; </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">int</span><span> fadeDelay, fadeDuration; </span></span></li><li class=""><span> <span class="keyword">private</span><span> </span><span class="keyword">float</span><span> ovalRadius; </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> Animation animFadeout; </span></span></li><li class=""><span> <span class="comment">/** RectF比Rect是精度上更精确。 */</span><span> </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> RectF rectFBody, rectFIndicator; </span></span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> SlidingIndicator(Context context, AttributeSet attrs, </span><span class="keyword">int</span><span> defStyle) { </span></span></li><li class=""><span> <span class="keyword">super</span><span>(context, attrs, defStyle); </span></span></li><li class="alt"><span> <span class="comment">// 预设值。</span><span> </span></span></li><li class=""><span> <span class="keyword">int</span><span> barColor = BAR_COLOR, highlightColor = HIGHLIGHT_COLOR; </span></span></li><li class="alt"><span> fadeDelay = FADE_DELAY; </span></li><li class=""><span> fadeDuration = FADE_DURATION; </span></li><li class="alt"><span> <span class="keyword">if</span><span> (attrs != </span><span class="keyword">null</span><span>) { </span></span></li><li class=""><span> TypedArray typedArr = context.obtainStyledAttributes(attrs, R.styleable.sliding_SlidingIndicator); </span></li><li class="alt"><span> barColor = typedArr.getColor(R.styleable.sliding_SlidingIndicator_barColor, BAR_COLOR); </span></li><li class=""><span> highlightColor = typedArr.getColor(R.styleable.sliding_SlidingIndicator_highlightColor, HIGHLIGHT_COLOR); </span></li><li class="alt"><span> fadeDelay = typedArr.getInteger(R.styleable.sliding_SlidingIndicator_fadeDelay, FADE_DELAY); </span></li><li class=""><span> fadeDuration = typedArr.getInteger(R.styleable.sliding_SlidingIndicator_fadeDuration, FADE_DURATION); </span></li><li class="alt"><span> ovalRadius = typedArr.getDimension(R.styleable.sliding_SlidingIndicator_roundRectRadius, 0f); </span></li><li class=""><span> typedArr.recycle(); </span></li><li class="alt"><span> } </span></li><li class=""><span> initialization(barColor, highlightColor, fadeDuration); </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> SlidingIndicator(Context context, AttributeSet attrs) { </span></span></li><li class=""><span> <span class="keyword">this</span><span>(context, attrs, </span><span class="number">0</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">public</span><span> SlidingIndicator(Context context) { </span></span></li><li class=""><span> <span class="keyword">super</span><span>(context); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">void</span><span> initialization(</span><span class="keyword">int</span><span> barColor, </span><span class="keyword">int</span><span> highlightColor, </span><span class="keyword">int</span><span> fadeDuration) { </span></span></li><li class=""><span> barPaint = <span class="keyword">new</span><span> Paint(); </span></span></li><li class="alt"><span> barPaint.setColor(barColor); </span></li><li class=""><span> </span></li><li class="alt"><span> highlightPaint = <span class="keyword">new</span><span> Paint(); </span></span></li><li class=""><span> highlightPaint.setColor(highlightColor); </span></li><li class="alt"><span> </span></li><li class=""><span> animFadeout = <span class="keyword">new</span><span> AlphaAnimation(1f, 0f); </span></span></li><li class="alt"><span> animFadeout.setDuration(fadeDuration); </span></li><li class=""><span> animFadeout.setRepeatCount(<span class="number">0</span><span>); </span></span></li><li class="alt"><span> animFadeout.setInterpolator(<span class="keyword">new</span><span> LinearInterpolator()); </span></span></li><li class=""><span> <span class="comment">// 设置动画结束后,本组件保持动画结束时的最后状态,即全透明不可见。</span><span> </span></span></li><li class="alt"><span> animFadeout.setFillEnabled(<span class="keyword">true</span><span>); </span></span></li><li class=""><span> animFadeout.setFillAfter(<span class="keyword">true</span><span>); </span></span></li><li class="alt"><span> </span></li><li class=""><span> rectFBody = <span class="keyword">new</span><span> RectF(); </span></span></li><li class="alt"><span> rectFIndicator = <span class="keyword">new</span><span> RectF(); </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> setPageAmount(</span><span class="keyword">int</span><span> num) { </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (num < </span><span class="number">0</span><span>) { </span></span></li><li class=""><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> IllegalArgumentException(</span><span class="string">"num must be positive."</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> amount = num; </span></li><li class="alt"><span> invalidate(); </span></li><li class=""><span> fadeOut(); </span></li><li class="alt"><span> } </span></li><li class=""><span> </span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">void</span><span> fadeOut() { </span></span></li><li class=""><span> <span class="keyword">if</span><span> (fadeDuration > </span><span class="number">0</span><span>) { </span></span></li><li class="alt"><span> clearAnimation(); </span></li><li class=""><span> <span class="comment">// 设置动画的延时时间,此时间段内正好指示当前页位置。</span><span> </span></span></li><li class="alt"><span> animFadeout.setStartTime(AnimationUtils.currentAnimationTimeMillis() + fadeDelay); </span></li><li class=""><span> setAnimation(animFadeout); </span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getCurrentPage() { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> currentPage; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> setCurrentPage(</span><span class="keyword">int</span><span> idx) { </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (currentPage < </span><span class="number">0</span><span> || currentPage >= amount) { </span></span></li><li class=""><span> <span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> IllegalArgumentException(</span><span class="string">"currentPage parameter out of bounds"</span><span>); </span></span></li><li class="alt"><span> } </span></li><li class=""><span> <span class="keyword">if</span><span> (</span><span class="keyword">this</span><span>.currentPage != idx) { </span></span></li><li class="alt"><span> <span class="keyword">this</span><span>.currentPage = idx; </span></span></li><li class=""><span> <span class="keyword">this</span><span>.position = currentPage * getPageWidth(); </span></span></li><li class="alt"><span> invalidate(); </span></li><li class=""><span> fadeOut(); </span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">void</span><span> setPosition(</span><span class="keyword">int</span><span> position) { </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (</span><span class="keyword">this</span><span>.position != position) { </span></span></li><li class=""><span> <span class="keyword">this</span><span>.position = position; </span></span></li><li class="alt"><span> invalidate(); </span></li><li class=""><span> fadeOut(); </span></li><li class="alt"><span> } </span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getPageWidth() { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> getWidth() / amount; </span></span></li><li class=""><span> } </span></li><li class="alt"><span> </span></li><li class=""><span> <span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> onDraw(Canvas canvas) { </span></span></li><li class="alt"><span> rectFBody.set(<span class="number">0</span><span>, </span><span class="number">0</span><span>, getWidth(), getHeight()); </span></span></li><li class=""><span> canvas.drawRoundRect(rectFBody, ovalRadius, ovalRadius, barPaint); </span></li><li class="alt"><span> rectFIndicator.set(position, <span class="number">0</span><span>, position + getPageWidth(), getHeight()); </span></span></li><li class=""><span> canvas.drawRoundRect(rectFIndicator, ovalRadius, ovalRadius, highlightPaint); </span></li><li class="alt"><span> } </span></li><li class=""><span>} </span></li></ol></div><pre name="code" class="java" style="display: none;">package lab.sodino.sliding;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
/**
* @author Sodino E-mail:sodinoopen@hotmail.com
* @version Time:2012-1-18 下午03:31:08
*/
public class SlidingIndicator extends View {
public static final int BAR_COLOR = 0xaa777777;
public static final int HIGHLIGHT_COLOR = 0xaa999999;
public static final int FADE_DELAY = 2000;
public static final int FADE_DURATION = 500;
private int amount, currentPage, position;
private Paint barPaint, highlightPaint;
private int fadeDelay, fadeDuration;
private float ovalRadius;
private Animation animFadeout;
/** RectF比Rect是精度上更精确。 */
private RectF rectFBody, rectFIndicator;
public SlidingIndicator(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 预设值。
int barColor = BAR_COLOR, highlightColor = HIGHLIGHT_COLOR;
fadeDelay = FADE_DELAY;
fadeDuration = FADE_DURATION;
if (attrs != null) {
TypedArray typedArr = context.obtainStyledAttributes(attrs, R.styleable.sliding_SlidingIndicator);
barColor = typedArr.getColor(R.styleable.sliding_SlidingIndicator_barColor, BAR_COLOR);
highlightColor = typedArr.getColor(R.styleable.sliding_SlidingIndicator_highlightColor, HIGHLIGHT_COLOR);
fadeDelay = typedArr.getInteger(R.styleable.sliding_SlidingIndicator_fadeDelay, FADE_DELAY);
fadeDuration = typedArr.getInteger(R.styleable.sliding_SlidingIndicator_fadeDuration, FADE_DURATION);
ovalRadius = typedArr.getDimension(R.styleable.sliding_SlidingIndicator_roundRectRadius, 0f);
typedArr.recycle();
}
initialization(barColor, highlightColor, fadeDuration);
}
public SlidingIndicator(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlidingIndicator(Context context) {
super(context);
}
private void initialization(int barColor, int highlightColor, int fadeDuration) {
barPaint = new Paint();
barPaint.setColor(barColor);
highlightPaint = new Paint();
highlightPaint.setColor(highlightColor);
animFadeout = new AlphaAnimation(1f, 0f);
animFadeout.setDuration(fadeDuration);
animFadeout.setRepeatCount(0);
animFadeout.setInterpolator(new LinearInterpolator());
// 设置动画结束后,本组件保持动画结束时的最后状态,即全透明不可见。
animFadeout.setFillEnabled(true);
animFadeout.setFillAfter(true);
rectFBody = new RectF();
rectFIndicator = new RectF();
}
public void setPageAmount(int num) {
if (num < 0) {
throw new IllegalArgumentException("num must be positive.");
}
amount = num;
invalidate();
fadeOut();
}
private void fadeOut() {
if (fadeDuration > 0) {
clearAnimation();
// 设置动画的延时时间,此时间段内正好指示当前页位置。
animFadeout.setStartTime(AnimationUtils.currentAnimationTimeMillis() + fadeDelay);
setAnimation(animFadeout);
}
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int idx) {
if (currentPage < 0 || currentPage >= amount) {
throw new IllegalArgumentException("currentPage parameter out of bounds");
}
if (this.currentPage != idx) {
this.currentPage = idx;
this.position = currentPage * getPageWidth();
invalidate();
fadeOut();
}
}
public void setPosition(int position) {
if (this.position != position) {
this.position = position;
invalidate();
fadeOut();
}
}
public int getPageWidth() {
return getWidth() / amount;
}
protected void onDraw(Canvas canvas) {
rectFBody.set(0, 0, getWidth(), getHeight());
canvas.drawRoundRect(rectFBody, ovalRadius, ovalRadius, barPaint);
rectFIndicator.set(position, 0, position + getPageWidth(), getHeight());
canvas.drawRoundRect(rectFIndicator, ovalRadius, ovalRadius, highlightPaint);
}
}</pre><br>
末尾,自己推荐另一个左右滑屏实现方法:ViewPager<br>
http://my.oschina.net/kzhou/blog/29157<br>
<pre></pre>
<pre></pre>
</pre>