基于Android的2D物理引擎游戏——魔法跳跳球的设计与实现外文翻译资料

 2022-09-15 15:12:00

英语原文共 564 页,剩余内容已隐藏,支付完成后下载完整资料


第八章2D与3D图形的绘制

Android组件和集合工具是很方便并且功能很强大,涵盖了各种各样的需求。当你需要的功能现有的组件无法实现的时候,会发生什么?比如说,你的应用程序需要完成模拟打扑克,展示月亮的相位,或者是将能量转移到火箭的主推进器中。在这种情况下,你必须要知道该如何完成你自己的需求。

本章是对Android图形和动画的概述。它是针对那些有图形方面知识的程序员来编写的,本章是对扭转和转到物体的方法进行一个更深层次的介绍。在阅读本章时,你肯定需要用到Android文档,特别是因为这个框架还在不断变化。在实现方面最主要的变化是有关蜂窝时间,举个例子,就是更好的利用硬件加速。它还从本质上影响了应用程序优化绘图的方法。还要说明的是,这项技术能够帮助你得到用户的赞赏。

设计你自己的组件

正如前面所提到的,组件(widget)只是一个方便的子类(android.view.View子类)术语,通常是视图树的一个叶节点,来实现视图及其控制器。视图树中的内部节点,虽然它们可能包含复杂的代码,但往往有更简单的用户交互。术语组件,虽然是非正式的,但通常保留用户界面的主要部分:用户关心的那些信息和行为。

你不创造一个新的组件也可以完成很多东西。像TextView,按钮,和日期选择器这些组件都是由Android UI工具包提供的。在这本书中,

我们已经构建了一些包括了几乎现有所有的预包装的组件或一些简单的现有组件的子类的应用程序。这些应用的代码只是建立树视图,将他们放在代码或通过布局资源放在在XML文件中。

我们将会在第九章中看到一个不平凡的MicroJobs的应用程序,有一个包含对应名称列表的视图来找到图上的位置。随着附加位置添加到图上,新的名称显示小部件被添加到该列表中。即使这个动态变化的布局只是使用预先存在的小部件,不创建新的。打个比方,在MicroJobs技术,从一棵树上拆装箱就像第6章图6-3说明的哪样。

一个可以嵌套其他小部件的更复杂的小部件,将有子类视图集,它本身就是一个视图的子类。一个非常复杂的小部件,也许是一个在几个地方使用的接口工具(即使是多个应用程序),可能是一个完整的类,其中只有一个是视图的后代。

本章展示了如何开发自己的部件,这包括视图引擎盖下的查看。它是关于图形的,即关于视图部分的模型—视图控制器(MVC)模式。正如前面提到的,小部件也包含控制器代码,这是一个很好的设计,因为它保留了一个行为及其在屏幕上的表现的所有代码。本章讨论的只是视图的设计。与控制器相关的讨论在第六章。

专注于图形,然后,我们可以把这一章的任务分为两个基本部分:发现屏幕空间、绘制整个空间。第一项任务被称为布局。叶片组件可以断言其空间需要定义一个onMeasure方法,安卓用户界面框架将在正确的时间调用。第二项任务,实际上是渲染插件,是通过插件中的onDraw方法。

布局

在安卓框架布局机制中,大部分重举都是由视图容器(container view)来实现的。视图容器是包含其他视图的视图。这是一个内部的树视图节点,是ViewGroup的子类。框架工具包提供各种先进的视图容器,以提供强大的和可适应的策略来安排屏幕。列举一些常见的布局,如LinearLayout和RelativeLayout,都是相对容易使用和不平凡的执行正确的视图容器。因为方便、强大的容器视图已经存在,你将可能没有必要实现一个布局或去讨论的布局算法。了解Android UI框架是如何管理布局过程的,将帮助您建立正确的,强大的组件。

例8-1展示了有可能是最简单的一个工作组件设计。如果添加到一些Activity的视图树中,这个小部件将会吧分配给它的空间颜色填充为青色。不是很有趣,但是在我们继续创建任何复杂的东西之前,让我们仔细看一下这个例子是如何满足布局和绘图这两个基本任务的。我们将从布局过程开始,之后我们将会在231页的画布绘图(Canvas Drawing)讨论绘图。

Example 8-1. A trivial widget

public class TrivialWidget extends View {

public TrivialWidget(Context context) {

super(context);

setMinimumWidth(100); setMinimumHeight(20);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

setMeasuredDimension(

getSuggestedMinimumWidth(),

getSuggestedMinimumHeight());

}

@Override

protected void onDraw(Canvas canvas) {

canvas.drawColor(Color.CYAN);

}

}

因为组件的空间需求是动态变化的,所以动态规划布局是必要的。例如,假设在全球定位系统中的一个小部件可以显示你目前正在行驶的城市的名称。当你从“Ely”到“Post Mills”,小部件接收位置的更改通知。当它准备重新划定城市的名字时,发现没有足够的空间为新城镇的名字。它需要请求赋予它更多的屏幕空间来重绘屏幕,如果可行的话将重新绘制屏幕。

布局可以是一个令人惊讶的复杂的任务,而且很难得到正确的结果。它可能不是很难在单一的设备上使一个特定的叶片部件看起来正确。它可能是非常棘手的,另一方面,要设计一个小组件,必须安排子节点在多个设备上查看,包括屏幕变化的尺寸。

布局过程是从对requestLayout方法在视图树上调用一些视图时开始的。通常情况下,当控件需要更多的空间时会调用它的requestLayout方法本身。虽然,该方法可以在应用程序的任何地方被调用,以表明在当前屏幕上的一些视图不再有正确房间。requestLayout方法会使Android UI框架在UI事件队列中插入事件。当事件被处理时,按顺序框架将给每一个容器视图一个机会来询问它的每个子部件如何绘制。这个过程分为两个阶段:测量子视图,然后安排他们的新位置。所有视图都必须实现第一个阶段,但是第二阶段只有在视图容器实现子视图的布局的管理时才需要。

测量

测量阶段的目标是为每个视图提供一个机会,以动态地请求它希望的空间。用户界面框架通过调用视图的根视图的方法来启动这个过程树。从那里开始,每一个容器视图都询问它的每一个孩子它想要的空间。这个调用按深度优先方法被传播给所有的后代,让每个孩子得到一个机会在父亲之前计算它的大小。父节点在孩子结点大小的基础上计算其自身大小,并将信息返回给它自己的父亲结点,以此类推直至整个树完成其空间分配。在175页的“渲染一个图形接口”,例如,最上面的线性布局(LinearLayout)要求每个嵌套LinearLayout组件的首选尺寸。他们轮流问他们包含的EditText或者按钮。每一个孩子都需要告诉父结点想要的大小。然后父亲再增加孩子以及其填充的大小,并且向顶层LinearLayout报告。

因为框架必须保证所有的视图行为都在进程中,这个视图的方法最终不能被重写。相反,测量调用的onMeasure方法可以被组件重写来声明自己的空间。有关onMeasure方法的讨论描述了父亲愿意提供的可以空间:以像素为单位的规范宽度和高度。该框架假定没有视图小于0或大于230像素,因此,采用了通过int参数的高阶位来编码测量规范模式。这就好像是onMeasure实际上是有四个参数:宽度规格模式,宽度,高度规范模式,高度。不要去尝试做你自己的位转来分开空间的竞争。相反,应该使用MeasureSpec.getSize, MeasureSpec.getMode静态方法。

规范模式描述了容器视图是如何让孩子理解相关尺寸的。下面给出三个参数:

Meas ureSpec.EXACTLY:

要调用的视图容器已经确定了孩子视图的精确大小。

MeasureSpec.AT_MOST:

要调用的视图容器设置了这个维度的最大尺寸,但是孩子可以自由地请求

小一点的尺寸。

MeasureSpec.UNSPECIFIED:

要调用的视图容器没有对孩子施加任何限制,孩子可以请求任何它选择的

东西。

一个小部件总是负责告诉它的父亲在视图树上它需要多少空间。它通过调用setMeasuredDimensions设置其高度和宽度的支柱。父母可以通过getMeasuredHeigh和getMeasuredWidth方法找回这些特性。如果你实现重写onMeasure但不调用setMeasuredDimensions,测量方法将抛出IllegalStateException异常来代替正常完成。

onMeasure()方法的默认实现,是继承自view的,每个方向的两个值之一通过setMeasuredDimensions来设置。如果父亲指定为MeasureSpec.UNSPECIFIED,孩子调用setMeasuredDimensions()方法设置视图的默认大小:值是由getSuggestedMinimumWidth()或getSuggestedMinimumHeight提供的。相反的,如果父指定另两种模式的一种则默认实现使用父提供的尺寸。这是一个非常合理的策略,允许一个典型的部件实现来完全地处理测量阶段,没有复杂的计算,使用getSuggestedMinimumWidth()或getSuggestedMinimumHeight()的返回值。

您的窗口小部件可能无法真正获得它所请求的空间。想象一个100像素宽,三个孩子的视图。如果孩子们要求的像素宽度的总和是100或更少,那么家长应该如何安排孩子的孩子是显而易见的。但是,如果每个孩子都请求50个像素,父视图容器将不能够满足他们所有的要求。

一个视图容器完全控制它如何安排它的孩子。在这种情况下,它可能会决定“公平”分配为每个孩子分配33个像素。同样的,它也可能给最左边的孩子分配50像素,另外两个孩子分配25像素。事实上,它还可能会决定给一个孩子的整个100像素而不分配给其他孩子。不管它的方法是什么,最终还是由父亲为每个孩子确定一个矩形边界的大小和位置。

例8-1的组件小实例是另一个容器视图控制器分配组件空间的例子。该实例演示了一个请求空间最小的策略,不管它是什么,它是提供的(不像默认的实现)。这个策略是很容易被组件记住的,将被添加到容器工具箱中不是用LinearLayout实现gravity。gravity是一个属性,用于指定其子元素的对齐方式。第一次使用这些容器时你可能会感到惊讶,在默认情况下,你的自定义窗口的只有第一个绘制!你可以利用SETGRAVITY方法改变Gravity.fill属性,或使您的部件坚持空间量要求来解决这个问题。同样重要的是要注意,一个容器视图可以在一个测量阶段中多次调用一个孩子的测量方法。一个巧妙的容器视图作为其实现onMeasure一部分试图制定出一个水平行的小工具,有可能使用MEASURE_SPEC.UNSPECIFIED模式和宽度为0来调用每个子部件的measure方法,来找出子部件想要的尺寸。一旦它的每个孩子收集的首选宽度,它可以比较实际宽度的总和(在其父调用中指定其测量方法)。现在它可以调用每个子控件的方法了,这一次使用宽度和MeasureSpec.AT_MOST模式来确定空间的实际可用合适比例。因为measure方法可能被多次调用,一个实现的onMeasure必须是幂等的,不能更改应用程序的状态。

如果执行一次的效果和执行多次是一样的,那么这个活动就可以说成是“幂等”。例如,声明x = 3是幂等的,无论你执行多少次都是3。然而,声明x=x 1,是不等幂的,因为x的值取决于你执行多少次语句。

对视图容器实现onMeasure方法可能是相当复杂的。View Group所有容器视图的子类没有提供默认实现。每个安卓用户界面框架容器视图都有它自己的onMeasure方法。如果你考虑实施一个容器视图,你可以考虑把它放在其中的一个view中。相反,如果你从零开始执行测量,你仍然可能需要调用每一个孩子的measure方法,你应该考虑使用ViewGroup的辅助方法:measureChildwithMargins、measureChild、measureChildren。

一个容器视图,在测量阶段的结论,像任何其他小部件一样,必须通过调用setMeasuredDimensions方法来报告需要的空间。

排版

一旦一个视图树上所有的容器视图在有一个机会来协商他们每一个孩子的大小,这个框架开始了布局的第二阶段,包括安排孩子。另外,除非你实现自己的容器视图,否则可能永远不必执行你自己的安排代码。本节描述底层的过程,这样您就可以更好地理解它如何影响你的小部件。在视图中实现默认的方法, 将为典型的叶组件工作,正如例8 - 1说明的那样。

因为一个视图的onMeasure方法可能被调用几次,所有框架必须使用不同的方法来衡量测量阶段完成是否完成,容器视图必须解决孩子的最

剩余内容已隐藏,支付完成后下载完整资料


资料编号:[148749],资料为PDF文档或Word文档,PDF文档可免费转换为Word

原文和译文剩余内容已隐藏,您需要先支付 30元 才能查看原文和译文全部内容!立即支付

以上是毕业论文外文翻译,课题毕业论文、任务书、文献综述、开题报告、程序设计、图纸设计等资料可联系客服协助查找。