博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 左右滑屏效果
阅读量:7022 次
发布时间:2019-06-28

本文共 10144 字,大约阅读时间需要 33 分钟。

View Code

以上xml文件中引用的guide_round.xml   (页面滑动下面的实心圈和空心圈)

View Code

自定义组件 SwitchLayout

View Code
public class SwitchLayout extends ViewGroup {    private int mCurScreen;    // 瞬间速度    private static final int SNAP_VELOCITY = 600;    // 改变imageView    private OnViewChangeListener onViewChangeListener;    // 拖动手势的速率跟踪器    private VelocityTracker tracker;    // 滚动控制器    private Scroller scroller;    private float mLastMotionX;    private Context context;    public SwitchLayout(Context context) {        super(context);        this.context = context;        init(context);    }    public SwitchLayout(Context context, AttributeSet attrs) {        super(context, attrs);        this.context = context;        init(context);    }    public SwitchLayout(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        this.context = context;        init(context);    }    /** 初始化控件 */     private void init(Context context) {        mCurScreen = 0;        scroller = new Scroller(context);    }    @Override /** 必须要调用的方法 目的:当前的view在给自己的子控件指派大小和位置必须要调用的方法 */    protected void onLayout(boolean changed, int l, int t, int r, int b) {        if (changed) {            int childLeft = 0;            int childCount = getChildCount();            for (int i = 0; i < childCount; i++) {                View childView = getChildAt(i);                if (childView.getVisibility() != View.GONE) {                    int childWidth = childView.getMeasuredWidth();                    // 子控件被填充在父控件中(第二个阶段,第一个阶段为onMeasure,即计算)                    childView.layout(childLeft, 0, childLeft + childWidth,                            childView.getMeasuredHeight());                    // 改变左边的起始位置                    childLeft += childWidth;                }            }        }    }    @Override  /** 计算控件的宽和高 */    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int width = MeasureSpec.getSize(widthMeasureSpec);        int count = getChildCount();        for (int i = 0; i < count; i++) {            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);        }        // 滚到到哪一屏,通过width来控制        scrollTo(mCurScreen * width, 0);    }    public void setOnViewChangeListener(OnViewChangeListener changeListener) {        this.onViewChangeListener = changeListener;    }    /**     * 设置自定义控件中的哪个子控件展示在当前屏幕中     * @param pos     */    public void snapToScreen(int pos) {        //System.out.println("当前的位置:" + pos);        if (getScrollX() != (pos * getWidth())) {            int destina = pos * getWidth() - getScrollX();// 要移动的距离            // 开始滚动,从起始地开始,后两个参数为滚动的距离。用坐标来表示            scroller.startScroll(getScrollX(), 0, destina, 0);            mCurScreen = pos;            // 在主线程中调用这个方法来重绘view,必须在主线程中调用            invalidate();            // 改变imageView的显示(根据guide_round.xml可以看出,当状态enabled的            // 的时候,用黑点表示,也就是不是当前选中。)            //System.out.println("ImageView改变监听" + onViewChangeListener);            if (onViewChangeListener != null) {                onViewChangeListener.onViewChange(pos);            }        }    }    @Override    public void computeScroll() {        if (scroller.computeScrollOffset()) {            scrollTo(scroller.getCurrX(), scroller.getCurrY());            postInvalidate();        }    }    @Override    public boolean onTouchEvent(MotionEvent event) {        // Return the kind of action being performed --        // one of either ACTION_DOWN, ACTION_MOVE, ACTION_UP, or ACTION_CANCEL.        int action = event.getAction();        /**         * 屏幕上的每一次触摸都会被onTouchEvent捕获到,可以从event得到其x,y的值。         * 特别注意:并且得到的是你当前的触点的x,y坐标的值,也就是说,往左划动的话, 你的x的值是变小的。         */        float x = event.getX();        //System.out.println("onTouchEvent--" + x);        switch (action) {        // 按下        case MotionEvent.ACTION_DOWN:            if (tracker == null) {                tracker = VelocityTracker.obtain();                tracker.addMovement(event);            }            if (!scroller.isFinished())                // 防止scroller滚动到最终的x和y的位置                scroller.abortAnimation();            mLastMotionX = x;            //System.out.println("mLastMotionX--" + mLastMotionX);            break;        // 移动        case MotionEvent.ACTION_MOVE:            // 开始位置的触点与当前位置的差值            int deltalX = (int) (mLastMotionX - x);            if (canMove(deltalX)) {                if (tracker != null) {                    tracker.addMovement(event);                }                mLastMotionX = x;                // 控件滚动的位置                scrollBy(deltalX, 0);            }            break;                // 松手        case MotionEvent.ACTION_UP:              /** 往左滑动,因为x是在减小,所以横向速率是负值。 往右滑动,因为x是在增大,所以横向速率是正值。 */            int velocityX = 0;            if (tracker != null) {                tracker.addMovement(event);                tracker.computeCurrentVelocity(1000);// 计算1s滚动的速度                //System.out.println("tracker -- " + tracker);                velocityX = (int) tracker.getXVelocity();// 得到最终的横向速率                //System.out.println("横向速率--" + velocityX);                //System.out.println("mCurScreen--" + mCurScreen);            }            // 不是第一屏,且是往右滑动            if (velocityX > SNAP_VELOCITY && mCurScreen > 0)                snapToScreen(mCurScreen - 1);            // 往左滑动,且不是最后一个            else if (velocityX < -SNAP_VELOCITY                    && mCurScreen < (getChildCount() - 1)) {                snapToScreen(mCurScreen + 1);            }            // 往左滑动,且是最后一个,这里直接finish掉activity            else if (velocityX == 0 && mCurScreen == (getChildCount() - 1)) {                //System.out.println("-----------");                Activity activity = (Activity) context;                Intent intent = new Intent();                intent.setClass(context, LandingTwoActivity.class);                context.startActivity(intent);                activity.finish();            }            else { // 速率不够快是,另一种跳转方式                snapToDestination();            }            if (tracker != null) {                tracker.recycle();                tracker = null;            }            break;        }        return true;    }    /** 滑动到下一屏 */     private void snapToDestination() {        int screenWidth = getWidth();        // 最终滑动的位置超过1\2时,才滚动,否则,destScreen得到将是当前屏的值。        int destScreen = (getScrollX() + screenWidth / 2) / screenWidth;        snapToScreen(destScreen);    }    /** 可滚动的条件 */     private boolean canMove(int deltalX) {        // getScrollX(),得到触点view在左边的x轴的坐标,它的值是从第一张图到最后一张图算的,        // 也就是说:getScrollX()得到的值是 将整个图展开,然后相对的那个x坐标。        // 显示的是第一张图,并且是往右划        if (getScrollX() <= 0 && deltalX < 0) {            return false;        }        // 显示的是最后一张图并且是往左划        if (getScrollX() >= (getChildCount() - 1) * getWidth() && deltalX > 0) {            return false;        }        return true;    }}

SetupPageActivity加载显示效果

View Code
public class SetupPageActivity extends Activity {    private static String TAG = "SetupPageActivity1";    private SwitchLayout switchLayout;    private LinearLayout linearLayout;    private TextView bottom_img[]; // 底部的ImageView    private int viewCount; // 自定义控件中子控件的个数    private int viewSel; // 当前选中的ImageView    @Override    protected void onCreate(Bundle savedInstanceState) {        // TODO Auto-generated method stub        super.onCreate(savedInstanceState);        requestWindowFeature(Window.FEATURE_NO_TITLE);        super.setContentView(R.layout.setup_page1);        init();    }    private void init() {        switchLayout = (SwitchLayout) findViewById(R.id.switchLayoutID);        linearLayout = (LinearLayout) findViewById(R.id.linerLayoutID);        // 得到子控件的个数        viewCount = switchLayout.getChildCount();        bottom_img = new TextView[viewCount];        // 设置imageView        for (int i = 0; i < viewCount; i++) {            // 得到LinearLayout中的子控件(底部)            bottom_img[i] = (TextView) linearLayout.getChildAt(i);            bottom_img[i].setEnabled(true); // 控件激活            bottom_img[i].setTag(i);            bottom_img[i].setOnClickListener(new MOnClickListener());            bottom_img[i].getPaint().setFakeBoldText(true);        }        // 设置第一个imageView不被激活        viewSel = -1;        int initCurScreen = 0;        setCurPoint(initCurScreen);        switchLayout.snapToScreen(initCurScreen);        // bottom_img[viewSel].setEnabled(false);        switchLayout.setOnViewChangeListener(new MOnViewChangeListener());    }    /** bottom_img点击事件的监听器 */    private class MOnClickListener implements OnClickListener {        @Override        public void onClick(View v) {            int pos = (Integer) v.getTag();            // 设置当前显示的ImageView            setCurPoint(pos);            // 设置自定义控件中的哪个子控件展示在当前屏幕中            switchLayout.snapToScreen(pos);        }    }    /** 设置当前显示的ImageView */    private void setCurPoint(int pos) {        if (pos < 0 || pos > viewCount - 1 || viewSel == pos)            return;        // 当前的imgaeView将可以被激活        if (viewSel != -1) {            bottom_img[viewSel].setEnabled(true);            bottom_img[viewSel].setText(" ");        }        // 将要跳转过去的那个imageView变成不可激活        bottom_img[pos].setEnabled(false);        //bottom_img[pos].setText(" " + (pos + 1)+" " );        viewSel = pos;    }    /** 自定义控件中View改变的事件监听 */    private class MOnViewChangeListener implements OnViewChangeListener {        @Override        public void onViewChange(int view) {            // TODO Auto-generated method stub            Log.i(TAG, "view:--" + view);            if (view < 0 || viewSel == view) {                return;            } else if (view > viewCount - 1) {                Log.i(TAG, "finish activity");                SetupPageActivity.this.finish();            }            setCurPoint(view);        }    }}

以上Activity使用到的接口

View Code
public interface OnViewChangeListener {   public void onViewChange(int view);}

 

 

转载地址:http://ucbxl.baihongyu.com/

你可能感兴趣的文章
LVS结合keepalived配置
查看>>
网站性能测试PV到TPS的转换以及TPS的波动
查看>>
umount 提示 device is busy
查看>>
支付宝和微信支付
查看>>
iptables详解与举例
查看>>
ls -l命令详解
查看>>
学习Xfire的一些体会
查看>>
redis 对list操作命令
查看>>
[转]layui数据表格(一:基础篇,数据展示、分页组件、表格内嵌表单和图片)...
查看>>
kvm创建快照与还原
查看>>
MYSQL 复制,重命名表
查看>>
关于微软将于4月8日正式停止对Windows XP系统的支持的感想
查看>>
七、编写每天定时切割Nginx日志的脚本【LNMP安装 】
查看>>
lambda和字典的例子
查看>>
REST与WebService的区别
查看>>
如何检测异方差并纠正它?
查看>>
drbd学习总结
查看>>
个人总结:网站被黑有哪些表现形式
查看>>
spring+mybatis简单框架搭建
查看>>
selinux的初级管理
查看>>