20189200余超 2018-2019-2 移动平台应用开发实践第九周作业

20189200余超 2018-2019-2 移动平台应用开发实践第九周作业

图形和制定视图

  1. Android视图系统、层次关系

 Android应用设计和Web应用设计类似,也分前端和后端设计。Android的核心要素和四大组件属于后端设计部分,UI设计属于前端设计。前端设计决定了用户体验的好坏,后端设计则决定了功能的完备和应用的安全、稳定。

 对Android的UI设计来说,用到的最重要的两个类是:View和ViewGroup。它们决定着展示给用户的外观界面的形状。下面介绍下Android视图系统的层次关系:

View 类是所有视图控件 (包括 ViewGroup) 的基类。 各种 UI 控件都继承 View类,通过实现不同的接口实现特定功能。关于继承关系,多说一下,方便大家更清楚的理解控件,见下图:图 2. 控件继承关系

图 3 . 常用的UI 控件

  1. Android 视图框架 MVC 模型
    Android 的 UI 框架也是采用的 MVC 进行组织的,它提供控制器处理用户输入,对模型做出相应操作,并将结果反馈到视图,重新构建视图、渲染到屏幕。

  2. Android 视图执行过程分析

  在 Android 的开发中,视图布局,采用 XML 文件编写,通过在 XML 文件中添加相应的控件,设置其属性达到布局的目的。一个简单的布局文件如下:

  demo.xml 文件内容


<?xml version="1.0" encoding="utf-8"?>   //声明xml文件编码及版本

<LinearLayout          //使用线性布局,对内部控件内部起作用,十七线性排列

 

//引用的命名空间

xmlns:android="http://schemas.android.com/apk/res/android"

 

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:padding="5dp"

android:orientation="vertical" >            //内部控件排列方向:垂直排列

 

<EditText             //添加一个文本输入框控件

android:id="@+id/show"              //设置该控件ID

 

//一下到结束为该控件的各种属性设置,使其在界面上显示出特定样式

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_marginTop="10dp"

android:layout_weight="2"

android:lines="3"

android:editable="false"

android:gravity="top|right"

android:cursorVisible="true"

android:text=""

android:textSize="24sp"

/>              //结束该控件

</LinearLayout>                 //布局结束标示

一个布局文件(demo.xml)创建好后,新建一个 Test.java 文件来使用该布局文件,如下:
  Test.java文件内容

片段

Fragment 表示 Activity 中的行为或用户界面部分。您可以将多个片段组合在一个 Activity 中来构建多窗格 UI,以及在多个 Activity 中重复使用某个片段。您可以将片段视为 Activity 的模块化组成部分,它具有自己的生命周期,能接收自己的输入事件,并且您可以在 Activity 运行时添加或移除片段(有点像您可以在不同 Activity 中重复使用的“子 Activity”)。

片段必须始终嵌入在 Activity 中,其生命周期直接受宿主 Activity 生命周期的影响。 例如,当 Activity 暂停时,其中的所有片段也会暂停;当 Activity 被销毁时,所有片段也会被销毁。 不过,当 Activity 正在运行(处于已恢复生命周期状态)时,您可以独立操纵每个片段,如添加或移除它们。 当您执行此类片段事务时,您也可以将其添加到由 Activity 管理的返回栈 — Activity 中的每个返回栈条目都是一条已发生片段事务的记录。 返回栈让用户可以通过按返回按钮撤消片段事务(后退)。

当您将片段作为 Activity 布局的一部分添加时,它存在于 Activity 视图层次结构的某个 ViewGroup 内部,并且片段会定义其自己的视图布局。您可以通过在 Activity 的布局文件中声明片段,将其作为 元素插入您的 Activity 布局中,或者通过将其添加到某个现有 ViewGroup,利用应用代码进行插入。不过,片段并非必须成为 Activity 布局的一部分;您还可以将没有自己 UI 的片段用作 Activity 的不可见工作线程。

本文描述如何在开发您的应用时使用片段,包括将片段添加到 Activity 返回栈时如何保持其状态、如何与 Activity 及 Activity 中的其他片段共享事件、如何为 Activity 的操作栏发挥作用等等。

设计原理
Android 在 Android 3.0(API 级别 11)中引入了片段,主要是为了给大屏幕(如平板电脑)上更加动态和灵活的 UI 设计提供支持。由于平板电脑的屏幕比手机屏幕大得多,因此可用于组合和交换 UI 组件的空间更大。利用片段实现此类设计时,您无需管理对视图层次结构的复杂更改。 通过将 Activity 布局分成片段,您可以在运行时修改 Activity 的外观,并在由 Activity 管理的返回栈中保留这些更改。

例如,新闻应用可以使用一个片段在左侧显示文章列表,使用另一个片段在右侧显示文章 — 两个片段并排显示在一个 Activity 中,每个片段都具有自己的一套生命周期回调方法,并各自处理自己的用户输入事件。 因此,用户不需要使用一个 Activity 来选择文章,然后使用另一个 Activity 来阅读文章,而是可以在同一个 Activity 内选择文章并进行阅读,如图 1 中的平板电脑布局所示。

您应该将每个片段都设计为可重复使用的模块化 Activity 组件。也就是说,由于每个片段都会通过各自的生命周期回调来定义其自己的布局和行为,您可以将一个片段加入多个 Activity,因此,您应该采用可复用式设计,避免直接从某个片段直接操纵另一个片段。 这特别重要,因为模块化片段让您可以通过更改片段的组合方式来适应不同的屏幕尺寸。 在设计可同时支持平板电脑和手机的应用时,您可以在不同的布局配置中重复使用您的片段,以根据可用的屏幕空间优化用户体验。 例如,在手机上,如果不能在同一 Activity 内储存多个片段,可能必须利用单独片段来实现单窗格 UI。

创建片段
想创建片段,您必须创建 Fragment 的子类(或已有其子类)。Fragment 类的代码与 Activity 非常相似。它包含与 Activity 类似的回调方法,如 onCreate()、onStart()、onPause() 和 onStop()。实际上,如果您要将现有 Android 应用转换为使用片段,可能只需将代码从 Activity 的回调方法移入片段相应的回调方法中。

通常,您至少应实现以下生命周期方法:

onCreate()
系统会在创建片段时调用此方法。您应该在实现内初始化您想在片段暂停或停止后恢复时保留的必需片段组件。
onCreateView()
系统会在片段首次绘制其用户界面时调用此方法。 要想为您的片段绘制 UI,您从此方法中返回的 View 必须是片段布局的根视图。如果片段未提供 UI,您可以返回 null。
onPause()
系统将此方法作为用户离开片段的第一个信号(但并不总是意味着此片段会被销毁)进行调用。 您通常应该在此方法内确认在当前用户会话结束后仍然有效的任何更改(因为用户可能不会返回)。
大多数应用都应该至少为每个片段实现这三个方法,但您还应该使用几种其他回调方法来处理片段生命周期的各个阶段。 处理片段生命周期部分对所有生命周期回调方法做了更详尽的阐述。

您可能还想扩展几个子类,而不是 Fragment 基类:

DialogFragment
显示浮动对话框。使用此类创建对话框可有效地替代使用 Activity 类中的对话框帮助程序方法,因为您可以将片段对话框纳入由 Activity 管理的片段返回栈,从而使用户能够返回清除的片段。
ListFragment
显示由适配器(如 SimpleCursorAdapter)管理的一系列项目,类似于 ListActivity。它提供了几种管理列表视图的方法,如用于处理点击事件的 onListItemClick() 回调。
PreferenceFragment
以列表形式显示 Preference 对象的层次结构,类似于 PreferenceActivity。这在为您的应用创建“设置” Activity 时很有用处。
添加用户界面
片段通常用作 Activity 用户界面的一部分,将其自己的布局融入 Activity。

要想为片段提供布局,您必须实现 onCreateView() 回调方法,Android 系统会在片段需要绘制其布局时调用该方法。您对此方法的实现返回的 View 必须是片段布局的根视图


图 2. 片段的生命周期(其 Activity 运行时)

多面板布局

1.layout_common.xml

复用的布局文件

<?xml version="1.0" encoding="utf-8"?>
<!-- 复用的布局文件 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1" />

    <Button
        android:id="@+id/common_button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="按钮1" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1" />

    <Button
        android:id="@+id/common_button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="按钮2" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1" />

    <Button
        android:id="@+id/common_button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="按钮3" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1" />

</LinearLayout>

2.layout_main.xml

主布局文件 ,在这里引用复用的布局文件

<?xml version="1.0" encoding="utf-8"?>
<!-- 主布局文件 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_margin="16dp"
        android:layout_weight="1" >
    </RelativeLayout>

    <!-- 在布局文件中引用复用的布局文件 -->

    <include layout="@layout/layout_common" />

</LinearLayout>

3.CommonView.java

复用布局文件实例化。单独封装,接口回调。 避免重复写布局文件,避免重复实例化控件,避免重复设置监听方法

package com.example.mytestapp;

import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

/**
 * 复用布局文件实例化
 */
public class CommonView implements OnClickListener {

    // 接口
    public interface OnCommonViewClick {
        public void onButton1Click(View v);

        public void onButton2Click(View v);

        public void onButton3Click(View v);
    }

    public void setListener(OnCommonViewClick listener) {
        this.listener = listener;
    }

    Context mContext;
    OnCommonViewClick listener;

    public CommonView(Context context) {
        this.mContext = context;
    }

    public Button button1, button2, button3;

    public CommonView init() {
        button1 = (Button) ((Activity) mContext).findViewById(R.id.common_button1);
        button2 = (Button) ((Activity) mContext).findViewById(R.id.common_button2);
        button3 = (Button) ((Activity) mContext).findViewById(R.id.common_button3);
        button1.setOnClickListener(this);
        button2.setOnClickListener(this);
        button3.setOnClickListener(this);
        return this;
    }

    @Override
    public void onClick(View v) {
        if (listener == null)
            return;
        switch (v.getId()) {
        case R.id.common_button1:
            listener.onButton1Click(v);
            break;
        case R.id.common_button2:
            listener.onButton2Click(v);
            break;
        case R.id.common_button3:
            listener.onButton3Click(v);
            break;
        default:
            break;
        }
    }

}

4.MainActivity.java

主界面实例化

package com.example.mytestapp;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

/*
 * 问题:
 * 1.如何用代码改变控件的文字或颜色?
 */

public class MainActivity extends Activity implements CommonView.OnCommonViewClick {

    int clickTimes = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_main);
        // 在这里实例化布局文件, 并实现监听接口方法
        // 只需要一行代码就可以直接完成复用代码块的实例化
        new CommonView(this).init().setListener(this);
    }

    @Override
    public void onButton1Click(View v) {
        clickTimes++;
        // 在这里实现对应点击事件的方法
        Toast.makeText(this, "你点击了button" + clickTimes + "次", Toast.LENGTH_SHORT).show();

    }

    @Override
    public void onButton2Click(View v) {
        // 在这里实现对应点击事件的方法
    }

    @Override
    public void onButton3Click(View v) {
        // 在这里实现对应点击事件的方法
    }

}

动画

. 属性动画出现的原因

属性动画(Property Animation)是在 Android 3.0(API 11)后才提供的一种全新动画模式
那么为什么要提供属性动画(Property Animation)?

1.1 背景
实现动画效果在Android开发中非常常见,因此Android系统一开始就提供了两种实现动画的方式:

逐帧动画(Frame Animation)
补间动画( Tweened animation )

1.2 问题
逐帧动画 & 补间动画存在一定的缺点:
a. 作用对象局限:View
即补间动画 只能够作用在视图View上,即只可以对一个Button、TextView、甚至是LinearLayout、或者其它继承自View的组件进行动画操作,但无法对非View的对象进行动画操作

有些情况下的动画效果只是视图的某个属性 & 对象而不是整个视图;
如,现需要实现视图的颜色动态变化,那么就需要操作视图的颜色属性从而实现动画效果,而不是针对整个视图进行动画操作

b. 没有改变View的属性,只是改变视觉效果

补间动画只是改变了View的视觉效果,而不会真正去改变View的属性。
如,将屏幕左上角的按钮 通过补间动画 移动到屏幕的右下角
点击当前按钮位置(屏幕右下角)是没有效果的,因为实际上按钮还是停留在屏幕左上角,补间动画只是将这个按钮绘制到屏幕右下角,改变了视觉效果而已。

c. 动画效果单一

补间动画只能实现平移、旋转、缩放 & 透明度这些简单的动画需求
一旦遇到相对复杂的动画效果,即超出了上述4种动画效果,那么补间动画则无法实现。

即在功能 & 可扩展性有较大局限性

1.3 问题

为了解决补间动画的缺陷,在 Android 3.0(API 11)开始,系统提供了一种全新的动画模式:属性动画(Property Animation)
下面,我将全面介绍属性动画(Property Animation)

  1. 简介

作用对象:任意 Java 对象

不再局限于 视图View对象

实现的动画效果:可自定义各种动画效果

不再局限于4种基本变换:平移、旋转、缩放 & 透明度

  1. 特点

作用对象进行了扩展:不只是View对象,甚至没对象也可以
动画效果:不只是4种基本变换,还有其他动画效果
作用领域:API11后引入的

  1. 工作原理

在一定时间间隔内,通过不断对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在该属性上的动画效果

可以是任意对象的任意属性

具体的工作原理逻辑如下:


从上述工作原理可以看出属性动画有两个非常重要的类:ValueAnimator 类 & ObjectAnimator 类
其实属性动画的使用基本都是依靠这两个类
所以,在下面介绍属性动画的具体使用时,我会着重介绍这两个类。

  1. 具体使用
    5.1 ValueAnimator类
    定义:属性动画机制中 最核心的一个类
    实现动画的原理:通过不断控制 值 的变化,再不断 手动 赋给对象的属性,从而实现动画效果。如图下:

    从上面原理可以看出:ValueAnimator类中有3个重要方法:

ValueAnimator.ofInt(int values)
ValueAnimator.ofFloat(float values)
ValueAnimator.ofObject(int values)

下面我将逐一介绍。
5.1.1 ValueAnimator.ofInt(int values)

作用:将初始值 以整型数值的形式 过渡到结束值

即估值器是整型估值器 - IntEvaluator

5.1.32ValueAnimator.ofObject()
作用:将初始值 以对象的形式 过渡到结束值
即通过操作 对象 实现动画效果

工作原理:

具体使用:

// 创建初始动画时的对象  & 结束动画时的对象
myObject object1 = new myObject();  
myObject object2 = new myObject();  

ValueAnimator anim = ValueAnimator.ofObject(new myObjectEvaluator(), object1, object2);  
// 创建动画对象 & 设置参数
// 参数说明
// 参数1:自定义的估值器对象(TypeEvaluator 类型参数) - 下面会详细介绍
// 参数2:初始动画的对象
// 参数3:结束动画的对象
anim.setDuration(5000);  
anim.start(); 

posted @ 2019-04-28 09:59  余超20189220  阅读(190)  评论(0编辑  收藏  举报