创新源于模仿之三:实现左右两个屏幕的切换



今天第三篇,模仿UCWEB的首页,做一个可以左右滑动的双屏。


 

其实要实现这个效果在Android中并非难事,因为官方的Launcher已经有现成的源代码放在那儿了,就是那个Workspace.java。大家可以去http://android.git.kernel.org/ 下载。

 

而我们要做的事情就是分析它并精简它(毕竟我们只是打算左右滑动罢了,并不需要能创建快捷方式文件夹之类的东西,更不需要在上面拖放图标)。

 

public class Workspace extends ViewGroup
 implements DropTarget, DragSource, DragScroller {

}

 

因此,不管是Drop还是Drag,统统不需要了:
 

public class Workspace extends ViewGroup {

}

 

同时,把那些个接口所要求实现的方法,以及那些与Drag/Drop相关的成员变量都去掉吧。
看看我精简后剩下什么成员变量:

 

    private static final int INVALID_SCREEN = -1;

    private int mDefaultScreen;

    private boolean mFirstLayout = true;

    private int mCurrentScreen;
    private int mNextScreen = INVALID_SCREEN;
    private Scroller mScroller;

    private float mLastMotionX;
    private float mLastMotionY;

    private final static int TOUCH_STATE_REST = 0;
    private final static int TOUCH_STATE_SCROLLING = 1;

    private int mTouchState = TOUCH_STATE_REST;

    private int mTouchSlop;

以上足矣。

 

然后在Eclipse中会有大量的错误,没关系,删吧。

 

addView 是用来在代码中添加新的子view的方法,不需要,我们只需要在layout xml中直接指定就好了。
getOpenFolder/getOpenFolders 文件夹相关的,当然不需要了。
addInCurrentScreen/addWidget 都没什么用处了,可以删掉。
与Cell相关的那些也可以删掉。

 

因为我们的代码不能直接访问mScrollX,所以需要换成getScrollX()。这一点是需要特别注意的。

 

看看我精简后都剩下些什么方法:

 

 

最后只要不报错,就OK了。

 

我们来分析一下几个关键的方法,其一是 onTouchEvent:

    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        final int action = ev.getAction();
        final float x = ev.getX();

        switch (action) {
        case MotionEvent.ACTION_DOWN:

            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
            }

            // Remember where the motion event started
            mLastMotionX = x;
            break;
        case MotionEvent.ACTION_MOVE:
     //跟着手指拖动屏幕的处理。
            if (mTouchState == TOUCH_STATE_SCROLLING) {
                // Scroll to follow the motion event
                final int deltaX = (int) (mLastMotionX - x);
                mLastMotionX = x;

                if (deltaX < 0) {
                    if (getScrollX() > 0) {
                     scrollBy(Math.max(-1*getScrollX(), deltaX), 0);
                    }
                } else if (deltaX > 0) {
                    final int availableToScroll = getChildAt(getChildCount() - 1).getRight() -
                            getScrollX() - getWidth();
                    if (availableToScroll > 0) {
                     scrollBy(Math.min(availableToScroll, deltaX), 0);
                    }
                }
            }
            break;
        case MotionEvent.ACTION_UP:
     //抬起手指后,切换屏幕的处理
            if (mTouchState == TOUCH_STATE_SCROLLING) {
             snapToDestination();
            }
            mTouchState = TOUCH_STATE_REST;
            break;
        case MotionEvent.ACTION_CANCEL:
            mTouchState = TOUCH_STATE_REST;
        }

        return true;
    }

 

其二 snapToDestination和snapToScreen:

 

   private void snapToDestination() {
 //计算应该去哪个屏
        final int screenWidth = getWidth();
        final int whichScreen = (getScrollX() + (screenWidth / 2)) / screenWidth;
 //切换
        snapToScreen(whichScreen);
    }

    void snapToScreen(int whichScreen) {
        if (!mScroller.isFinished()) return;

        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
        boolean changingScreens = whichScreen != mCurrentScreen;

        mNextScreen = whichScreen;

        View focusedChild = getFocusedChild();
        if (focusedChild != null && changingScreens && focusedChild == getChildAt(mCurrentScreen)) {
            focusedChild.clearFocus();
        }

        //让mScroller启动滚动
        final int cx = getScrollX();
        final int newX = whichScreen * getWidth();
        final int delta = newX - cx;
        mScroller.startScroll(cx, 0, delta, 0, Math.abs(delta) * 4);
        invalidate();
    }

 

其三 computeScroll,让Workspace滚动到合适的位置:

 

    @Override
    public void computeScroll() {
        if (mScroller.computeScrollOffset()) {
            scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
            postInvalidate();
        } else if (mNextScreen != INVALID_SCREEN) {
            mCurrentScreen = Math.max(0, Math.min(mNextScreen, getChildCount() - 1));
            mNextScreen = INVALID_SCREEN;
        }

    }

 

基本上就是这些了,其它方法都是辅助的,很好理解。

 

其实有一个问题,我们发现UCWeb主页下面有三个点指示当前所处的位置,这个指示器我的想法是可以放在Workspace外面来做,利用Workspace当前的mCurrentScreen值显示出当前正处于哪个屏。

 

给出我的layout xml描述:

 

        <cn.sharetop.demo.ui.Workspace
         android:id="@id/friends_switcher"
         android:layout_width="fill_parent"
         android:layout_height="640.0dip"
         android:layout_weight="1.0"
         xmessenger:defaultScreen="0"
         >
         <include layout="@layout/screen1" />
         <include layout="@layout/screen2" />

        </cn.sharetop.demo.ui.Workspace>
       <TextView
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:textColor="#000000"
         android:background="@android:color/transparent"
         android:gravity="center"
         android:text="[1]2" />

 

就这样了。这个分页指示器就留给你自己去发挥了。

时间: 2024-09-13 08:04:38

创新源于模仿之三:实现左右两个屏幕的切换的相关文章

ViewPager实现左右两个屏幕的切换

项目终于需要这样的效果了,采用ViewPager去实现吧,让网上那些乱七八糟的屏幕切换类都终结了吧,ViewPager是google官方的!  下面是我借鉴的文章:  起初最早接触到左右两个屏幕切换的是在 <创新源于模仿之三:实现左右两个屏幕的切换> 这篇文章上,感谢作者为我们提供了这么好的DEMO.  什么是ViewPager呢?  它是实现左右两个屏幕平滑地切换的一个类,它是Google提供的,作为Android的一个补充.先上个效果图把,让大家有个直观的认识.    我们在网上搜索这相关

创新源于模仿之一:TabActivity的美化

  今天开始一个新专题:创新源于模仿. 第一篇从TabActivity着手,一直以为Android中的TabActivity只能放在上面,只能如此丑陋,直到有一天看到"米聊". 咋一看,软件下面的那个菜单栏,觉得像是用LinearLayout+Button来实现的,但事实上,它却是一个Tab! 怎么看出来的?我就不多说了,你懂的. 下面我们来抽丝剥茧,一步步分析它的实现过程. 1.TabActivity的布局 <TabHost xmlns:android="http:/

创新源于模仿之二:美化ListView的尝试

  今天继续,模仿MIUI做那个Contacts的ListView,如下图:       其实可以这样归纳一下我们要做的事情: 1. 按首字母分组,显示一个分组的标签头. 2. 在右边做一个全字母表,可以用手指上下滑动快速选择字母分组. 3. 再做一个当前选中的那个字母的显示. 先说第一件事.我们已经了解ListView/ListAdapter组合做出一个列表界面.那么,怎么在列表中显示一些不可选且模样不同的行,在SDK提供的例子其实是有相关代码可供参考的. 相关的代码是在ListAdapter

创新源于模仿之六:仿iPhone的分组列表做一个配置界面

  这个效果现在很多见了,象新浪微博客户端的"我的资料",MIUI中的设置,米聊中的"名片",,,等等等等.iPhone啊,你让Android程序员伤不起.     这个功能的实现很简单,如果你想简单的话,就是一个图片和布局的问题.今天继续拿来主义,反编译一下米聊的代码,从它的res里寻找我们需要的东西.   在res/drawable-hdpi/namecard_xxxxxxx 这些图片就是我们需要的资源,小米的设计人员做的图就是精细,比新浪的好多了.   使用上

创新源于模仿之五:做一个自己的QuickAction

 有一段时间没有上来折腾这个专题了,一来项目的确紧张,二来自己一惯是很懒的. 今天想与大家分享的是一个QuickAction的东西,模样其实就是通讯录中点击头像后弹出的那个提供可操作按钮的窗口.     这个效果其实我们也用过,就是QuickContactBadge.显然,它很有意思,但是为什么只能由系统决定上面的按钮呢? 所以今天我们要做的事情就是做一个自己的QuickAction类. 第一步:收集资源 去Android的源代码网站 http://android.git.kernel.org/

创新源于模仿之四:增强的ExpandableListView

  继续讨论一下如何实现手机QQ里那个增强版的ExpandableListView效果,如下图:     Android缺省的ExpandableListView的group header无法固定在界面上,当向下滚动后,不能对当前显示的那些child 指示出它们归属于哪个group,而这一点,在iphone中的tableview就做的非常好.   所以,我们来做一个固定在列表上方的提示框,显示当前显示的展开的那些child归属的group信息.   思路: 1. 先弄一个TextView作为指示

创新Or模仿?浅谈“山寨”圈里的云计算

本文讲的是创新Or模仿?浅谈"山寨"圈里的云计算[IT168 评论]当我们谈起山寨的时候,往往是带有嘲弄或自嘲的成分,假装欺骗,实为恶搞."山寨"是一种由民间IT力量发起的产业现象,从山寨手机.数码产品.山寨品牌开始,近年来,"山寨"已经上升为一种文化.任何事物,一旦上升成为一种文化,也就意味着它具有着广义的文化的特征:反映着整个社会的政治和经济,同时作用于社会政治和经济,山寨也是如此. ▲图1 山寨街 云计算领域三大"寨主"

jquery实现两个图片渐变切换效果的方法

  本文实例讲述了jquery实现两个图片渐变切换效果的方法.分享给大家供大家参考.具体如下: 这段代码演示了jquery如何实现两个图片渐变切换的效果,为id=kitten的div设置一个背景图片,通过jquery对div进行淡入淡出实现两个图片的渐变切换 html代码 ? 1 2 3 <div id="kitten"> <img src="/images/kitten.jpg" alt="Kitten" /> <

Win8两种安全模式互相切换图形

  1.Windows 8系统进入安全模式后不把安全引导勾选去掉,就会一直进入安全模. 图1 2.在进入系统后,按Win+R运行输入msconfig确定选择--引导--把安全引导勾选中确定重启后就可以进入Win8安全模式. 图2 3.在全安模式下按Win+R运行输入ghostxp系统下载msconfig确定选择--引导--把安全引导勾选去掉确定重启后就可以进入Win8安常模式. 安全模式的功能是对系统的安全有一定的保护的,所以以上就是说明两种安全模式互相切换的说明,更加方便了我们进入安全模式功能