加入收藏 | 设为首页 | 会员中心 | 我要投稿 开发网_郴州站长网 (http://www.0735zz.com/)- 云通信、区块链、物联设备、云计算、站长网!
当前位置: 首页 > 教程 > 正文

Android开发教程:左右滑屏的达成

发布时间:2021-12-18 14:31:34 所属栏目:教程 来源:互联网
导读:实现左右滑屏核心类是Scroller,将View中的内容左右滚动从而实现滑屏效果。关键方法有: scroller.scrollTo(x,y): 直接将View中的内容滚动到指定的(x,y)位置。 scroller.scrollTo(dx,dy): 直接将View中的内容滚动到相对当前状态的(dx,dy)位置。本例中用于实

实现“左右滑屏”核心类是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()方法中为本组件的动画设置了延时,体验上更亲近:
 
[java]
animFadeout.setStartTime(AnimationUtils.currentAnimationTimeMillis() + fadeDelay);  
setAnimation(animFadeout);  
代码如下(Java奉上,XML代码请各位看官自己实现):
 
 
ActSlidingContainer.java
 
[java]
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);  
    }  
}  
[java]
<pre name="code" class="java" style="background-color: rgb(255, 255, 255); "><pre>  
SlidingContainer.java
 
[java]
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);  
    }  
}  
SlidingIndicator.java
[java]
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);  
    }  
}  

(编辑:开发网_郴州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读