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

简介:
今天第三篇,模仿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" />


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

相关文章
|
2月前
|
图形学 开发者 存储
超越基础教程:深度拆解Unity地形编辑器的每一个隐藏角落,让你的游戏世界既浩瀚无垠又细节满满——从新手到高手的全面技巧升级秘籍
【8月更文挑战第31天】Unity地形编辑器是游戏开发中的重要工具,可快速创建复杂多变的游戏环境。本文通过比较不同地形编辑技术,详细介绍如何利用其功能构建广阔且精细的游戏世界,并提供具体示例代码,展示从基础地形绘制到植被与纹理添加的全过程。通过学习这些技巧,开发者能显著提升游戏画面质量和玩家体验。
94 3
|
2月前
|
人工智能 Unix 物联网
揭秘操作系统演进奇迹:从单一孤岛到多元宇宙的跨越,你的每一次点击背后有何奥秘?
【8月更文挑战第28天】操作系统的演进是一段从简单单一到复杂多元的壮丽旅程。自计算机诞生以来,操作系统作为硬件与软件的桥梁,不断推动信息技术的发展。从早期ENIAC的硬编码指令到IBM OS/360的批处理系统,再到UNIX的多用户多任务能力,操作系统逐步实现了真正的并发执行。21世纪,Windows以图形界面称霸个人电脑市场,Linux则在服务器和云计算领域大放异彩,macOS也在创意产业中占据重要地位。示例代码展示了在Linux下创建和运行新进程的方法。未来,操作系统将在物联网、人工智能等新兴技术的推动下继续进化,构建更智能、高效的数字世界。
26 1
|
2月前
|
C# Windows 监控
WPF应用跨界成长秘籍:深度揭秘如何与Windows服务完美交互,扩展功能无界限!
【8月更文挑战第31天】WPF(Windows Presentation Foundation)是 .NET 框架下的图形界面技术,具有丰富的界面设计和灵活的客户端功能。在某些场景下,WPF 应用需与 Windows 服务交互以实现后台任务处理、系统监控等功能。本文探讨了两者交互的方法,并通过示例代码展示了如何扩展 WPF 应用的功能。首先介绍了 Windows 服务的基础知识,然后阐述了创建 Windows 服务、设计通信接口及 WPF 客户端调用服务的具体步骤。通过合理的交互设计,WPF 应用可获得更强的后台处理能力和系统级操作权限,提升应用的整体性能。
87 0
|
2月前
|
开发者 图形学 Java
Unity物理引擎深度揭秘:从刚体碰撞到软体模拟,全面解析实现复杂物理交互的技巧与秘诀,助你打造超真实游戏体验
【8月更文挑战第31天】物理模拟在游戏开发中至关重要,可让虚拟世界更真实。Unity作为强大的跨平台游戏引擎,内置物理系统,支持从刚体碰撞到布料模拟的多种功能。通过添加Rigidbody组件,可实现物体受力和碰撞;使用AddForce()施加力;通过关节(如Fixed Joint)连接刚体以模拟复杂结构。Unity还支持软体物理,如布料和绳索模拟,进一步增强场景丰富度。掌握这些技术,可大幅提升游戏的真实感和玩家体验。
68 0
|
2月前
|
开发者 图形学 前端开发
绝招放送:彻底解锁Unity UI系统奥秘,五大步骤教你如何缔造令人惊叹的沉浸式游戏体验,从Canvas到动画,一步一个脚印走向大师级UI设计
【8月更文挑战第31天】随着游戏开发技术的进步,UI成为提升游戏体验的关键。本文探讨如何利用Unity的UI系统创建美观且功能丰富的界面,包括Canvas、UI元素及Event System的使用,并通过具体示例代码展示按钮点击事件及淡入淡出动画的实现过程,助力开发者打造沉浸式的游戏体验。
69 0
|
2月前
|
人工智能 JSON 自然语言处理
🔍深度揭秘!如何用提示词驾驭生成式大模型,让你的创意无限飞🌈
【8月更文挑战第1天】在AI风潮中,生成式大模型因出色的内容创造能力备受创意工作者青睐。但如何巧妙运用提示词,激发模型潜力,仍是挑战。本文通过问答形式揭秘提示词技巧:理解其定义、掌握设计方法(明确目标、具象描述、考虑模型特性)、评估其影响力及调整策略(细化描述、变换风格、调节参数),并分享实用贴士,助您成为驾驭AI创作的高手。
131 7
|
4月前
全息近眼显示技术如何实现三维图像再现?
【6月更文挑战第26天】全息近眼显示技术如何实现三维图像再现?
38 4
|
人工智能 测试技术
「化腐朽为神奇」:Stability AI又出新工具,草图瞬间精致,不同风格随心选
「化腐朽为神奇」:Stability AI又出新工具,草图瞬间精致,不同风格随心选
106 0
|
Java 计算机视觉
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏04图像资源的透明处理
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏04图像资源的透明处理
118 0
|
Java
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏06加载游戏背景
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏06加载游戏背景
127 0