




已阅读5页,还剩10页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Overheard Word 的单词和手势2014-09-28 14:30 佚名 ibm 字号:T | TOverheard Word 一直运行得很好,现在,我们已经开始在基本的 Android 外壳之上添加一些更有趣的特性。当然,还有更多的事情要做,但我们现在拥有一个正常运作的应用程序,它可以处理滑动,有图标和菜单,甚至可以从一个自定义 的第三方单词文件中读取。下个月,我会告诉您如何在 Overheard Word 中添加更多样式,然后实现一个灵活的测验特性。AD: 2014WOT全球软件技术峰会北京站 课程视频发布 11月21日-22日 与WOT技术大会相约深圳 现在抢票 以编程方式将第三方的代码集成到您的 Android UI从 GitHub 或另一个存储库采集第三方代码,可能让您觉得自己像在糖果店里的小孩一样,但还是需要一些技巧来将这些代码与您的 Android UI 相集成。这个月,Andrew Glover 将向您展示如何利用基于 JSON 的单词引擎和一些预焙制的滑动手势功能,将 Overheard Word 演示应用程序提升一个层次。事实证明,Android 可以轻松容纳第三方代码,但如果希望应用程序的 UI 可以顺利地运行它,您仍然必须执行一些缜密的逻辑。如果您到目前为止已经阅读并遵循本系列中的演示,那么就已经建立了一些基本的 Android 开发技能。除了搭建一个 Android 开发环境并编写您的第一个 Hello World 应用程序,您已经学会了如何在一个自定义的移动应用程序中用滑动手势代替按钮轻触,并实施菜单(或工具栏)和图标。在本文中,您继续沿着这条轨迹,学习如 何使用第三方库来增加或增强应用程序的功能。首先,我们将安装一些开源库并读取文件,然后将以编程方式集成新的功能与一个演示应用程序的 UI。正如我在以前的文章中所做的,我会用我的 Overheard Word 应用程序进行演示。如果您还没有克隆 Overheard Word 的 GitHub 库,您应该先这成这一步,以便可以执行后面的步骤。关于本系列移 动应用程序发布正呈现爆炸式增长,移动开发技术正当其时。本系列文章将向那些有编程经验但又刚刚接触移动领域的开发人员介绍这个领域的发展情况。本系列首 先使用 Java 代码编写本机应用程序,然后扩展您的工具箱,包括 JVM 语言、脚本框架、HTML5/CSS/JavaScript、第三方工具等。您将逐步掌握所需的技能,以便满足几乎所有移动开发场景的需求。Thingamajig:一个可插拔的单词引擎Overheard Word 是英语语言的应用程序,可以帮助用户学习新单词,并动态建立词汇表。在以前的文章中,我们首先开发了一个基本的应用程序,然后增加了 滑动手势 实现更方便的导航,并增加了 图标 形成更漂亮的 UI。到目前为止,一切都很好,但这个应用程序不会走得很远,因为它缺少某种成分:Overheard Word 需要一些单词!为了使 Overheard Word 成为真正的多词 应用程序,我已经建立了一个小型单词引擎 Thingamajig,它封装单词的概念及其相应的定义。Thingamajig 处理通过 JSON 文档创建单词及其定义,并且完全没有依赖于 Android。像 Overheard Word 应用程序一样,我的单词引擎 托管在 GitHub 上。您可以克隆存储库,或下载源代码,然后运行 ant。您最后会获得一个 8KB 的轻量级 JAR 文件,可以将该文件复制到您的 libs 目录中。如果您的 Android 项目已正确设置,那么 IDE 会自动将 libs 目录中的任何文件识别为一个依赖关系。当时,我的单词引擎中的代码是通过 JSON 文档实例进行初始化的。JSON 文档可以是驻留在设备上的文件系统中的一个文件、对 HTTP 请求的响应,甚至是对数据库查询的响应 就目前来说,这并不重要。重要的是,您有一个实用的库,让您可以使用 Word 对象。每个 Word 对象包含一个 Definition 对象的集合,以及一个相应的词性。虽然单词及其定义之间的关系远不是如此简单,但它现在是可行的。之后,我们可以添加例句、同义词和反义词。Android 中的第三方库将第三方库集成到 Android 项目很容易;事实上,每一个 Android 启动项目都包括一个特殊的目录 libs,您可以将第三方 JAR 放在该目录中。在 Android 的构建过程中,普通的 JVM 文件和第三方 JAR 都被转换为可以兼容 Dalvik(这是专用的 Android VM)。环境约束虽然您可以想像得到如何将喜欢的任何第三方库添加到应用程序中,但永远不要忘记移动环境的局限性。运行您的应用程序的设备毕竟不是什么可靠的 Web 服务器!用户会感谢您提高数据处理的能力,并尽可能减少第三方附件的下载大小。除了将单词引擎库插入到我的应用程序中,我还准备添加另一个 名称为 Gesticulate 的第三方应用程序。就像使用单词引擎库一样,您可以通过从 GitHub 上 克隆或下载 它的源代码来获得 Gesticulate。然后运行 ant,您会得到一个 JAR 文件,您可以将这个文件放进应用程序的 libs 目录。更新 UI现在,我们进入本文的核心,即更新 UI,以集成您刚刚免费抢购到的所有第三方代码。幸运的是,我利用我的 Overheard Word 应用程序提前为这一刻做好了计划。回到我编写该应用程序的 第一次迭代 时,我定义了一个简单的布局,其中包括一个单词、其词性,以及一个定义,如 图 1 所示:图 1. Overheard Word 的默认视图该布局使用占位符文本定义,我准备使用从我的可插拔单词引擎获取的实际单词替换占位符文本。所以,我会初始化一系列单词,抓取其中一个,并使用其值相应地更新 UI。为了更新 UI,我必须能够获得每个视图元素的一个句柄,并为这些元素提供值。例如,一个显示的单词(如 Pedestrian)被定义为一个 TextView,其 ID 是 word_study_word,如 清单 1 所示:清单 1. 在一个布局中定义的 TextView1. 如果您仔细看的话,就会发现我已经在 XML 中将文本设置为 “Word”;但是,我能够以编程方式,通过获取 TextView 实例的引用,并调用 setText 来设置该值。在可以进行下一步之前,我需要建立一个单词列表。您或许还记得我的单词引擎可以通过 JSON 文档创建 Word 实例,因此,我需要做的只是设置我的 Android 应用程序,让它包括并读取这些自定义文件。使用文件:res 和 raw 目录默认情况下,一个 Android 应用程序具有读取设备的基础文件系统的权限,但您只可以访问应用程序本身下面的本地文件系统。因此,您可以在您的应用程序中包括文件,并相应地引用它们。(这意味着,您可以读取和写入相对于您的应用程序是本地 的文件;写入到 SD 卡等在您的应用程序之外的文件系统则需要专门的权限。)因为我的单词引擎可以采用一个 JSON 文档来初始化单词列表,所以就没有什么可以阻止我包括一个应用程序会在运行时读取的 JSON 文档。就像在我以前的文章中所演示的图标资产一样,您可以将文件存储在 res 目录中。如果我发现自己需要自定义文件,我喜欢将它们添加到被称为 raw 的一个目录中。我放在该目录中的任何文件都可以通过生成的 R 文件来引用,我在 Overheard Word 中已经使用过几次该文件。基本上,Android 平台利用来自 res 目录的资产,并建立一个名称为 R 的类,然后,该类为这些资产提供一个句柄。如果资产是一个文件,那么 R 文件将提供一个引用,以打开文件并获取其内容。我在 res 目录结构中创建一个 raw 目录,并将一个 JSON 文档放在该目录中,如 图 2 所示:图 2. 包含新单词的 raw 目录接下来,Eclipse 重新构建项目,而我的 R 文件可以方便地引用新文件,如 图 3 所示:图 3. 更新后的 R 文件当我有一个文件的句柄时,我就可以打开它,读取它,并最终构建一个 JSON 文档来作为生成一个单词列表的基础。构建一个单词列表当应用程序启动时,我就开始执行一系列步骤,加载原始 JSON 文档,并构建一个单词列表。我将创建一个名称为 buildWordList 的方法来处理这些步骤,如 清单 2 所示:清单 2. 在 Android 中读取文件的内容1. privateListbuildWordList()2. InputStreamresource=3. getApplicationContext().getResources().openRawResource(R.raw.words);4. Listwords=newArrayList();5. try6. StringBuildersb=newStringBuilder();7. BufferedReaderbr=newBufferedReader(newInputStreamReader(resource);8. Stringread=br.readLine();9. while(read!=null)10. sb.append(read);11. read=br.readLine();12. 13. JSONObjectdocument=newJSONObject(sb.toString();14. JSONArrayallWords=document.getJSONArray(words);15. for(inti=0;iallWords.length();i+)16. words.add(Word.manufacture(allWords.getJSONObject(i);17. 18. catch(Exceptione)19. Log.e(APP,ExceptioninbuildWordList:+e.getLocalizedMessage();20. 21. returnwords;22. 您应该注意到在 buildWordList 方法中执行的一些操作。首先,请注意如何使用 Android 平台的调用创建 InputStream,Android 平台的调用最终引用在 raw 目录中发现的 words.json 文件。我没有使用 String 来代表路径,这使得代码可跨多种设备进行移植。接下来,我使用包含 在 Android 平台中的一个简单的 JSON 库,将内容(通过 String 表示)转换成一系列的 JSON 文档。在 Word 上的静态方法 manufacture 读取一个 JSON 文档,该文档代表一个单词。单词的 JSON 格式如 清单 3 所示:清单 3. JSON 代表一个单词1. 2. spelling:sagacious,3. definitions:4. 5. part_of_speech:adjective,6. definition:havingorshowingacutementaldiscernment7. andkeenpracticalsense;shrewd8. 9. 10. 我的 WordStudyEngine 类是 Thingamajig 的主要外观。它从 Word 实例列表产生随机单词和函数。所以,我的下一步是利用新建的 WordList 初始化引擎,如 清单 4 所示:清单 4. 初始化 WordStudyEngine1. Listwords=buildWordList();2. WordStudyEngineengine=WordStudyEngine.getInstance(words);当有一个已初始化的引擎实例,我就可以向其请求一个单词(自动随机排列),然后相应地更新 UI 的三个元素。例如,我可以更新定义的单词 部分,如 清单 5 所示:清单 5. 以编程方式更新 UI 元素1. WordaWord=engine.getWord();2. TextViewwordView=(TextView)findViewById(R.id.word_study_word);3. wordView.setText(aWord.getSpelling();清单 5 中的 findViewById 是一个 Android 平台调用,它读取一个整数 ID,您可以从您的应用程序的 R 类中获得该 ID。您能够以编程方式将文本设置为 TextView。您也可以设置字体类型,字体颜色,或文字显示的大小,类似于这样:wordView.setTextColor(Color.RED)。在 清单 6 中,我基本上按照相同的流程来更新应用程序的 UI 的定义和词性元素:清单 6. 更多编程式更新1. DefinitionfirstDef=aWord.getDefinitions().get(0);2. TextViewwordPartOfSpeechView=(TextView)findViewById(R.id.word_study_part_of_speech);3. wordPartOfSpeechView.setText(firstDef.getPartOfSpeech();4. 5. TextViewdefView=(TextView)findViewById(R.id.word_study_definition);6. defView.setText(formatDefinition(aWord);请注意在 清单 5 和 清单 6 中,如何使用 R 文件按名称引用布局元素。驻留在我的 Activity 类中的 formatDefinition 方法读取一个定义字符串,并将其首字母变成大写。该方法还格式化字符串,若句末没有句号,它就会在句末使用一个句号。(请注意,Thingamajig 与格式化没有任何关系 它只是一个单词引擎!)我已完成这些 UI 元素的更新,所以就可以启动我的应用程序,并检查结果。瞧!我现在要学习一个合法的单词!图 4. Overheard Word 有单词了!添加手势:将滑动连接到单词现在,我可以有效地显示一个单词,我希望让用户能够快速滑动我的单词引擎中的所有单词。为了更简单,我准备使用 Gesticulate,这是我自己的第三方库,可以计算滑动速度和方向。我也把滑动逻辑放进一个名称为 initializeGestures 的方法中。初始化了滑动手势后,第一步是将显示一个单词的逻辑移动到一个新方法中,当有人滑动时,我可以调用该方法来显示一个新单词。更新后的 onCreate 方法(最初是在 Android 创建应用程序实例时调用它)如 清单 7 所示:清单 7. 当初始化手势时,onCreate 即可显示一个单词1. protectedvoidonCreate(BundlesavedInstanceState)2. super.onCreate(savedInstanceState);3. Log.d(APP,onCreatedInvoked);4. setContentView(R.layout.activity_overheard_word);5. 6. initializeGestures();7. 8. Listwords=buildWordList();9. 10. if(engine=null)11. engine=WordStudyEngine.getInstance(words);12. 13. WordfirstWord=engine.getWord();14. displayWord(firstWord);15. 请注意 engine 变量,我将它定义为 OverheardWord Activity 本身的一个 private static 成员变量。我将简单地解释为什么要这样做。接下来,我进入 initGestureDetector 方法,如果您按照所克隆的代码,就会发现在 initializeGestures 方法中引用了它。如果你还记得,initGestureDetector 方法有一个逻辑,当用户在设备屏幕上向上、向下、向左或向右滑动时,它就会执行一个操作。在 Overheard Word 中,当用户从右到左滑动时(这是左滑),我想显示一个新单词。我首先删除 Toast 消息,这是该代码的占位符,将其替换为一个对 displayWord 的调用,如 清单 8 所示:清单 8. 当向左滑动时,initGestureDetector 即可显示一个单词1. privateGestureDetectorinitGestureDetector()2. returnnewGestureDetector(newSimpleOnGestureListener()3. publicbooleanonFling(MotionEvente1,MotionEvente2,4. floatvelocityX,floatvelocityY)5. try6. finalSwipeDetectordetector=newSwipeDetector(e1,e2,velocityX,velocityY);7. if(detector.isDownSwipe()8. returnfalse;9. elseif(detector.isUpSwipe()10. returnfalse;11. elseif(detector.isLeftSwipe()12. displayWord(engine.getWord();13. elseif(detector.isRightSwipe()14. Toast.makeText(getApplicationContext(),15. RightSwipe,Toast.LENGTH_SHORT).show();16. 17. catch(Exceptione)18. returnfalse;19. 20. );21. 我的单词引擎由 engine 变量表示,它需要在整个 Activity 中都可以被访问。这就是为什么我将其定义为一个成员变量,以确保每次有左滑时都会显示一个新单词。来回滑动现在,当打开应用程序,并开始滑动,每当向左滑动时,我都会看到显示一个新单词和定义。但是,当向其他方向滑动时,我只会得到一条微小的消息,显示我已经滑动了。如果我能够通过向右滑动回到前一个单词,岂不是更好吗?回退似乎不应该是困难的。也许我可以使用一个堆栈,只是弹出由前一次左滑放在那里的最高元素?但是,当用户在回退后再次左滑时,这种想法是站不住脚的。如果最高的位置被弹出,则将显示一个新 单词,而不是用户以前看到的单词。仔细思考后,我倾向于尝试一个链表的方法,当用户来回滑动时,可以摆脱之前浏览的单词。我将首先创建所有已显示单词的一个 LinkedList,如 清单 9 所示。然后,我会保持让一个指针指向该列表中的元素的索引,我可以用它来检索已经看到的单词。当然,我会将这些定义为 static 成员变量。我也将我的指针初始化为 -1,并且每当将一个新单词添加到 LinkedList 实例时,我就将其递增。就像任何语言中大部分类似于数组支持的集合一样,LinkedList 是从 0 开始建立索引。清单 9. 新的成员变量1. privatestaticLinkedListwordsViewed;2. privatestaticintviewPosition=-1;在 清单 10 中,我将我的应用程序的 onCreate 中的 LinkedList 初始化:清单 10. 初始化 LinkedList1. if(wordsViewed=null)2. wordsViewed=newLinkedList();3. 现在,当显示第一个单词时,我需要将其添加到 LinkedList 实例(wordsViewed)并递增指针变量 viewPosition,如 清单 11 所示:清单 11. 不要忘记递增视图位置1. WordfirstWord=engine.getWord();2. wordsViewed.add(firstWord);3. viewPosition+;4. displayWord(firstWord);滑动的逻辑现在,我进入逻辑 的主要部分,这需要一些思考。当用户向左滑动时,我想显示下一个单词,当他或她向右滑动时,我要显示前一个单词。如果用户再次向右滑动,那么应该显示第二 个之前的单词,以此类推。应该继续该操作,直到用户回到第一个显示的单词。然后,如果用户开始再次向左滑动,单词列表应该以和之前相同的顺序出现。最后的 部分有点棘手,因为我的 WordStudyEngine 的默认实现是以随机的 顺序返回一个单词。在 清单 12 中,我觉得自己已经解决了想要执行的操作的逻辑。第一个布尔值赋值被封装在一个称为 listSizeAndPositionEql 的方法中,它很简单:wordsViewed.size() = (viewPosition + 1)。如果 listSizeAndPositionEql 被赋值为 true,那么应用程序通过 displayWord 方法显示一个新单词。然而,如果 listSizeAndPositionEql 是 false,那么用户必须向后滑动;因此,使用 viewPosition 指针从列表中检索相应的单词。清单 12. 用于来回滚动的 LinkedList1. publicbooleanonFling(MotionEvente1,MotionEvente2,floatvelX,floatvelY)2. try3. finalSwipeDetectordetector=newSwipeDetector(e1,e2,velX,velY);4. if(detector.isDownSwipe()5. returnfalse;6. elseif(detector.isUpSwipe()7. returnfalse;8. elseif(detector.isLeftSwipe()9. if(listSizeAndPosi
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 不明原因消化道出血的管理2025
- 智慧港口-基于二三维一体化GIS与AI大模型技术的可视化监管平台解决方案
- (新版)焊工职业技能考试题库及答案(含各题型)
- 内蒙古兴安盟科尔沁右翼前旗第二中学2024-2025学年高一下学期6月月考语文试题(含答案)
- 希望杯初三试题及答案
- 河南省南阳市内乡县实验高级中学2025届高三下学期考前热身练政治试卷(含答案)
- 2025年陕西省西安市高新第一中学中考数学七模试卷(含部分答案)
- 2025年福建省厦门中考英语二模卷
- 推动家电公司数字化转型与智能化应用
- 《2025年代理收付款项服务合同》
- 电工基本知识培训资料课件
- 《园林花卉学》课后题及答案
- 某市道路客运班线管理台账
- 消防档案范本(企业类)
- 消防安全管理评分表
- 国际足联球员经纪人规则
- 电梯更换钢丝绳施工方案
- 植物保护学考试复习资料
- 科学二年级第二学期双减期末综合测评方案
- 6.医院感染综合性监测制度
- 贯彻三标一规范咨询工作计划
评论
0/150
提交评论