CH10-图形图像处理

2023-11-14

目标

  • 掌握常用绘图类的使用 ,能够绘制不同的图形
  • 掌握Matrix类的使用方式 ,能够实现为图片添加特效的功能
  • 掌握动画的使用 ,能够实现补间动画与逐帧动画的效果

​ 图形图像在Android应用中会经常用到,如一些程序的图标、界面的美化等都离不开图形图像。Android系统对图形图像的处理非常强大,对于2D图像它没有沿用Java中的图形处理类,而是使用了自定义的处理类,接下来本章将针对Android常用的绘图类、图形图像特效以及动画进行讲解

一、常用的绘图类

目标

  • 掌握常用绘图类的使用 ,能够绘制不同的图形

​ Android中常用的绘图类有Bitmap类、BitmapFactory类、Paint类以及Canvas类,通过对这几个类的使用可以分别实现创建位图、将指定资源解析为位图、创建画笔、绘制画布等功能。

  • Bitmap类:可以获取图像文件信息,对图像进行剪切、旋转、缩放等操作,并可以指定格式保存图像文件。

  • BitmapFactory类:是位图工厂,它是一个工具类。

  • Paint类:代表画笔,用来描述图形的颜色及风格。

  • Canvas类:代表画布,通过该类提供的方法,可以绘制各种图形。

1.1 Bitmap类

Bitmap类提供了一些静态方法,具体如下表所示。

方法名称 功能描述
createBitmap(int width, int height, Config config) 创建位图,width代表要创建的图片的宽度,height代表高度,config代表图片的配置信息
createBitmap(int colors[], int offset, int stride,int width, int height, Config config) 使用颜色数组创建一个指定宽高的位图,颜色数组的个数为width*height
createBitmap(Bitmap src) 使用源位图创建一个新的位图
createBitmap(Bitmap source, int x, int y, int width, int height) 从源位图的指定坐标开始剪切指定宽高的一块图像,用于创建新的位图
createBitmap(Bitmap source, int x, int y, int width, int height,Matrix m, boolean filter) 按照Matrix规则从源位图的指定坐标开始剪切指定宽高的一块图像,用于创建新的位图。

image-20220306230411804

1.2BitmapFactory类

方法名称 功能描述
decodeFile(String pathName) 将指定路径的文件解码为位图
decodeStream(InputStream is) 将指定输入流解码为位图
decodeResource(Resources res, int id) 将给定的资源id解析为位图
Bitmap bitmap = 
         BitmapFactory.decodeResource(this.getResources(),R.drawable.icon);
//通过decodeResource()方法将drawable文件夹中的icon.png图片资源解码为位图

1.3 Paint类

方法名称 功能描述
setARGB(int a, int r, int g, int b) 设置颜色,各参数值均为0~255之间的整数,几个参数分别用于表示透明度、红色、绿色和蓝色的值
setColor(int color) 设置颜色
setAlpha(int a) 设置透明度
setAntiAlias(boolean aa) 设置画笔是否使用抗锯齿功能
setTextAlign(Align align) 设置绘制文本时的文字对齐方式。参数值为Align.CENTER、Align.LEFT、Align.RIGHT,分别表示居中,左或右对齐
setTextSize(float textSize) 设置绘制文本时的文字大小
setFakeBoldText(boolean fakeBoldText) 设置绘制文字时是否为粗体文字
setDither(boolean dither) 指定是否使用图像抖动处理,如果使用会使图像颜色更加平滑、饱满、清晰
setShadowLayer(float radius, float dx, float dy, int color) 设置阴影。radius表示阴影的角度,dx和dy表示阴影在x轴和y轴上的距离,color表示阴影的颜色
setXfermode(Xfermode xfermode) 设置图像的混合模式

接下来定义一个画笔,并指定该画笔的颜色为红色,示例代码如下:

Paint paint = new Paint();
paint.setColor(Color.RED);	//指定画笔颜色为红色

1.4 Canvas类

方法名称 功能描述
drawRect(Rect r, Paint paint) 使用画笔绘制矩形
drawOval(RectF oval, Paint paint) 使用画笔绘制椭圆形
drawCircle(float cx, float cy, float radius, Paint paint) 使用画笔在指定位置画出指定半径的圆
drawLine(float startX, float startY, float stopX, float stopY, Paint paint) 使用画笔在指定位置画线
drawRoundRect(RectF rect, float rx, float ry, Paint paint) 使用画笔绘制指定圆角矩形,其中rx表示X轴圆角半径,ry表示Y轴圆角半径

在View的onDraw()方法中使用画笔Paint在画布上绘制矩形。

protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    Paint paint  = new Paint(); //创建画笔        
    paint.setColor(Color.RED);
    Rect r = new Rect(40,40,200,100); //构建矩形对象并指定位置、宽高
    canvas.drawRect(r,paint);         //调用绘制矩形的方法  
}

1.5 实战演练—绘制小狗

​ 本节我们将通过一个绘制小狗的案例来演示如何使用这些常用的绘图类,本案例的界面效果如下图所示。

image-20220306231257587

绘制小狗的自定义View类 drawdog\DrawView.java

package cn.itcast.drawdog;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

public class DrawView extends View {
    private Context mContext;
    public DrawView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext=context;
    }
    @Override
    protected void onDraw(Canvas canvas) {
        this.setBackgroundResource(R.drawable.bg);//设置画布的背景图片
        //将dog.png图片资源解码为位图
        Bitmap dogBitmap = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.dog);
        Paint paint = new Paint();//创建画笔
        canvas.drawBitmap(dogBitmap, 300, 550,paint);  //绘制图片
    }
}

放置界面控件 res\layout\activity_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">
    <cn.itcast.drawdog.DrawView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

二、为图像添加特效

目标

  • 掌握Matrix类的使用方式,能够实现为图片添加特效的功能
特效 方法名称 功能描述
平移 setTranslate(float dx,float dy) 指定图像在X、Y轴移动dx和dy的距离
平移 preTranslate(float dx, float dy) 使用前乘的方式计算在X、Y轴平移的距离。
平移 postTranslate(float dx,float dy) 使用后乘的方式计算在X、Y轴平移的距离。
旋转 setRotate(float degrees) 指定图片旋转degrees度
旋转 preRotate(float degrees) 使用前乘的方式指定图片旋转degrees度
旋转 postRotate(float degrees, float px, float py) 使用后乘的方式控制Matrix以参数px和py为轴心旋转degrees度
缩放 setScale(float sx, float sy) 指定图像在X轴和Y轴的缩放比例为sx和sy
缩放 preScale(float sx, float sy) 使用前乘的方式计算图像在X轴和Y轴的缩放比例
缩放 postScale(float sx, float sy) 使用后乘的方式计算图像在X轴和Y轴的缩放比例
倾斜 setSkew(float kx, float ky) 指定图像在X、Y轴的倾斜值
倾斜 preScale(float kx, float ky) 使用前乘的方式设置图像在X、Y轴的倾斜值
倾斜 postScale(float kx, float ky) 使用后乘的方式设置图像在X、Y轴的倾斜值

接下来我们通过一个案例来演示如何使用Matrix类为图片添加特效。本案例的界面效果如下图所示。

image-20220306231437296

创建TranslateView类 specialeffect\TranslateView.java

package cn.itcast.specialeffect;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

public class TranslateView extends View {
    public TranslateView(Context context) {
        super(context);
    }
    public TranslateView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public TranslateView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();     //创建画笔
//        将图片husky.png解析为bitmap位图对象
        Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.husky);
        Matrix matrix = new Matrix(); //创建一个矩阵
        matrix.setTranslate(100,100); //将矩阵向右(X轴)平移100,向下(Y轴)平移100
        canvas.drawBitmap(bitmap, matrix, paint);//将图片按照矩阵的位置绘制到界面上
    }
}

引用TranslateView类 res\layout\activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <cn.itcast.specialeffect.TranslateView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    </cn.itcast.specialeffect.TranslateView>
</RelativeLayout>

三、动画

目标

  • 掌握动画的使用,能够实现补间动画与逐帧动画的效果

​ 在Android开发中,避免不了用到动画,Android系统给我们提供了三种实现动画效果的方式,分别为补间动画、逐帧动画和属性动画

image-20220306231551889

3.1 补间动画

在Android中,提供了四种补间动画

image-20220306231644273

透明度渐变动画

透明度渐变动画是通过改变View组件透明度来实现的渐变效果。它主要通过指定动画开始时View的透明度、结束时View的透明度以及动画持续时间来实现的。

image-20220307101208317

旋转动画

​ 旋转动画是通过对View指定动画开始时的旋转角度、结束时的旋转角度以及动画播放时长来实现的。

image-20220307101235309

pivotX: 可选50、50%、50%p (p表示parent)

  • 50: 表示在当前View左上角的X轴坐标加上50px的位置,作为旋转点的x轴坐标
  • 50%: 表示在当前View左上角的X轴坐标加上View自己宽度的50%的位置,作为旋转点的x轴坐标
  • 50%p: 表示在当前View左上角的X轴坐标加上父控件宽度的50%的位置,作为旋转点的x轴坐标

缩放动画

​ 缩放动画是通过对动画指定开始时的缩放系数、结束时的缩放系数以及动画持续时长来实现的。

image-20220307101259714

平移动画

​ 平移动画是通过指定动画的开始位置、结束位置以及动画持续时长来实现的。

image-20220307101321779

接下来,我们通过一个案例来演示4种补间动画的效果。本案例的界面效果如下图所示。

image-20220307101414768

image-20220307101427372

放置界面控件 res\layout\activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginBottom="5dp">
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/iv_tween"
        android:layout_centerInParent="true"
        android:id="@+id/iv_bean"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true">
        <Button
            android:id="@+id/btn_one"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="渐变"/>
        <Button
            android:id="@+id/btn_two"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="旋转"/>
        <Button
            android:id="@+id/btn_three"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="缩放"/>
        <Button
            android:id="@+id/btn_four"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="移动" />
    </LinearLayout>
</RelativeLayout>

实现补间动画的4种效果 tween\MainActivity.java

package cn.itcast.tween;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button buttonOne;
    private Button buttonTwo;
    private Button buttonThree;
    private Button buttonFour;
    private ImageView ivBean;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化控件并为对应的控件加添点击事件的监听器
        buttonOne = findViewById(R.id.btn_one);
        buttonTwo = findViewById(R.id.btn_two);
        buttonThree = findViewById(R.id.btn_three);
        buttonFour = findViewById(R.id.btn_four);
        ivBean = findViewById(R.id.iv_bean);
        buttonOne.setOnClickListener(this);
        buttonTwo.setOnClickListener(this);
        buttonThree.setOnClickListener(this);
        buttonFour.setOnClickListener(this);
    }
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_one: //"渐变"按钮的点击事件
                Animation alpha = AnimationUtils.loadAnimation(this,
                        R.anim.alpha_animation);
                ivBean.startAnimation(alpha);
                break;
            case R.id.btn_two: //"旋转"按钮的点击事件
                Animation rotate = AnimationUtils.loadAnimation(this,
                        R.anim.rotate_animation);
                ivBean.startAnimation(rotate);
                break;
            case R.id.btn_three://"缩放"按钮的点击事件
                Animation scale = AnimationUtils.loadAnimation(this,
                        R.anim.scale_animation);
                ivBean.startAnimation(scale);
                break;
            case R.id.btn_four: //"平移"按钮的点击事件
                Animation translate = AnimationUtils.loadAnimation(this,
                        R.anim.translate_animation);
                ivBean.startAnimation(translate);
                break;
        }
    }
}

3.2 逐帧动画

逐帧动画是按照准备好的静态图像顺序播放的,利用人眼的“视觉暂留”原理,造成动画的错觉。

逐帧动画的原理与放胶片看电影的原理是一样的,它们都是一张一张地播放事先准备好的静态图像。

​ 接下来,我们通过一个案例来讲解如何使用帧动画来实现动态的Wi-Fi信号效果。本案例的界面效果如下图所示。

image-20220307101551713

image-20220307101600668

放置界面控件 res\layout\activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    tools:context=".MainActivity">
    <ImageView
        android:id="@+id/iv_wifi"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="100dp"
        android:layout_marginBottom="20dp"
        android:background="@drawable/frame" />
    <Button
        android:id="@+id/btn_play"
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:layout_below="@+id/iv_wifi"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="20dp"
        android:background="@android:drawable/ic_media_play" />
</RelativeLayout>

创建动画资源 res\drawable\frame.xml

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:drawable="@drawable/wifi01" android:duration="300"></item>
    <item android:drawable="@drawable/wifi02" android:duration="300"></item>
    <item android:drawable="@drawable/wifi03" android:duration="300"></item>
    <item android:drawable="@drawable/wifi04" android:duration="300"></item>
    <item android:drawable="@drawable/wifi05" android:duration="300"></item>
    <item android:drawable="@drawable/wifi06" android:duration="300"></item>
</animation-list>

实现逐帧动画的效果 frame\MainActivity.java

package cn.itcast.frame;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener
{
    private ImageView iv_wifi;
    private Button btn_start;
    private AnimationDrawable animation;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        iv_wifi = findViewById(R.id.iv_wifi);
        btn_start = findViewById(R.id.btn_play);
        btn_start.setOnClickListener(this);
        //获取AnimationDrawable对象
        animation = (AnimationDrawable) iv_wifi.getBackground();
    }
    @Override
    public void onClick(View v) {
        if (!animation.isRunning()) { //如果动画当前没有播放
            animation.start();//播放动画
            btn_start.setBackgroundResource(android.R.drawable.ic_media_pause);
        } else {
            animation.stop(); //停止动画
            btn_start.setBackgroundResource(android.R.drawable.ic_media_play);
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(animation.isRunning()){
            animation.stop();
        }
        iv_wifi.clearAnimation();//清空控件的动画
    }
}

3.3 属性动画

在Android 3.0之后,Android系统给我们提供了一种全新的动画模式,属性动画(Property Animation),它是一种不断地对属性值进行操作的模式,也就是可以将值赋值到指定对象的指定属性上,该指定属性可以是任意对象的任意属性。通过属性动画我们仍然可以对一个View进行移动、缩放、旋转和透明度渐变等操作,同时也可以对自定义View中的Point(点)对象进行动画操作,在实现这些动画操作时,我们只需要设置动画的运行时长、动画的类型、动画属性的初始值和结束值即可

属性动画弥补了补间动画的一些缺陷,例如补间动画只能作用在View上,只能对View实现移动、缩放、旋转和透明度渐变动画,只能改变View的位置,不能对View自身进行修改。

1.Animator类

接下来针对属性动画的Animator类、评估程序、插值器、动画监听器进行详细讲解。

类名 说明
ValueAnimator 属性动画的主计时引擎,它也可以计算要添加动画效果的属性值。它具有计算属性值所需要的核心功能,同时包含每个动画的计时详情、有关动画是否重复播放的信息、用于接收更新事件的监听器以及设置待评估自定义类型的功能
ObjectAnimator ValueAnimator的子类,用于设置目标对象和对象属性以添加动画效果
AnimatorSet 此类提供一种将所有动画组合在一起的机制,使这些动画可以一起运行。我们可以将动画设置为一起播放、按顺序播放或者在指定的延迟时间后播放

使用ValueAnimator类添加动画效果

​ 我们可以调用ValueAnimator类中的ofInt()方法、ofFloat()方法或ofObject()方法来获取要添加动画效果的值。以获取float类型的动画效果值为例,示例代码如下。

ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f); //获取float类型的动画效果值
animation.setDuration(1000); 		//设置动画播放时长
animation.start();             		//开始播放动画

使用ObjectAnimator类添加动画效果

​ 当实例化ObjectAnimator类时,可以指定需要添加动画的对象与该对象属性的名称,同时还可以指定在哪些值之间添加动画效果。

//获取float类型的动画效果值
//translationX		表示动画的对象相对于最初位置的x轴方向的偏移量
//100f				表示动画的结束值
ObjectAnimator animation = ObjectAnimator.ofFloat(textView,"translationX", 100f); 	
animation.setDuration(1000); 	//设置动画播放时长
animation.start();      		//开始播放动画       

使用AnimatorSet类添加多个动画效果

​ 通常情况下,我们会遇到根据一个动画的开始或结束时间来播放另一个动画。在Android系统中,我们可以将这些需要一起播放的动画存放在AnimatorSet类中,便于指定这些动画是同时播放、按顺序播放、还是在指定的延迟时间后播放,同时我们还可以使用AnimatorSet类播放另一个AnimatorSet类对象中的动画。

2.评估程序

​ 评估程序(类/接口)主要用于告知属性动画系统如何计算指定属性的值。评估程序使用Animator 类提供的计时数据(动画的起始值和结束值)来计算属性添加动画效果后的值。

类名/接口名 说明
IntEvaluator 用于计算int类型的属性值的默认评估程序
FloatEvaluator 用于计算float类型的属性值的默认评估程序
ArgbEvaluator 用于计算颜色类型的属性值(用十六进制值表示)的默认评估程序
TypeEvaluator 此接口用于自定义一个评估程序。如果要添加动画效果的对象属性值不是int类型、float类型或颜色类型,那么必须实现TypeEvaluator接口,才能指定如何计算对象的属性添加动画效果之后的值。

3.插值器

​ 插值器Interpolator(类/接口)指定了如何根据时间计算动画中的特定值。android.view.animation包中包含的插值器如下表所示。

类名/接口名 说明
AccelerateDecelerateInterpolator 该插值器的变化率在开始和结束时缓慢但在中间会加快
AccelerateInterpolator 该插值器的变化率在开始时较为缓慢,然后会加快
AnticipateInterpolator 该插值器先反向变化,然后再急速正向变化
AnticipateOvershootInterpolator 该插值器先反向变化,再急速正向变化,然后超过定位值,最后返回到最终值

动画监听器

​ 动画监听器(一个接口)主要用于监听动画播放期间的重要事件,动画监听器有Animator.AnimatorListener和ValueAnimator.AnimatorUpdateListener。

(1)Animator.AnimatorListener

​ 动画监听器Animator.AnimatorListener(接口)中有4个方法,如下所示:

  • onAnimationStart():动画开始播放时调用该方法。

  • onAnimationEnd():动画结束播放时调用该方法。

  • onAnimationRepeat():动画重复播放时调用该方法。

  • onAnimationCancel():动画取消播放时调用该方法,取消动画时也会调用onAnimationEnd()方法。

(2)ValueAnimator.AnimatorUpdateListener

​ 动画监听器ValueAnimator.AnimatorUpdateListener中只有1个方法onAnimationUpdate(),该方法在动画播放的每一帧都会被调用。如果使用ValueAnimator.AnimatorUpdateListener监听某个动画播放的每一帧事件,那么可以调用ValueAnimator类的getAnimatedValue()方法获取动画添加完效果之后生成的值。

​ 如果某个类中使用了ValueAnimator类,那么该类必须实现ValueAnimator.AnimatorUpdateListener监听器。

3.4 实战演练—飞舞的蝴蝶和鸟

​ 本节我们通过一个综合案例飞舞的蝴蝶和鸟来演示如何使用逐帧动画与属性动画,本案例的界面效果如下图所示。

image-20220307102535234

放置界面控件 res\layout\activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg">
    <ImageView
        android:id="@+id/iv_bird"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:layout_marginTop="20dp"
        android:background="@drawable/bird_animation" />
    <ImageView
        android:layout_marginBottom="100dp"
        android:layout_alignParentBottom="true"
        android:id="@+id/iv_butterfly"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:layout_marginTop="20dp"
        android:background="@drawable/butterfly_animation" />
</RelativeLayout>

实现界面效果 butterfliesandbirds\MainActivity.java

package cn.itcast.butterfliesandbirds;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity {
    private int screenWidth;
    private ImageView iv_butterfly,iv_bird;
    private AnimationDrawable animation;
    private AnimatorSet flyAnimatorSet;
    private ObjectAnimator objectAnimator;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }
    private void init(){
        getWindowWidth();
        iv_butterfly=findViewById(R.id.iv_butterfly);
        iv_bird=findViewById(R.id.iv_bird);
        flyAnimation(1); //实现蝴蝶飞舞的效果
        flyAnimation(2); //实现小鸟飞舞的效果
    }
    /**
     * 获取屏幕宽度
     */
    private void getWindowWidth(){
        DisplayMetrics dm=new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(dm);
        screenWidth= dm.widthPixels;
    }
    /**
     * 实现飞舞的效果
     */
    private void flyAnimation(int flag){
        flyAnimatorSet=new AnimatorSet();
        if (flag==1) {
            //获取逐帧动画
            animation= (AnimationDrawable) iv_butterfly.getBackground();
            //设置蝴蝶在水平方向移动的距离为屏幕的宽度-270
//            translationX      水平方向移动
            objectAnimator = ObjectAnimator.ofFloat(iv_butterfly,
                    "translationX", screenWidth - 270);
            objectAnimator.setDuration(3*1000);//设置动画时间为3秒
        }else if (flag==2){
            //获取逐帧动画
            animation= (AnimationDrawable) iv_bird.getBackground();
            //设置小鸟在水平方向移动的距离为屏幕的宽度
            objectAnimator = ObjectAnimator.ofFloat(iv_bird,
                    "translationX", screenWidth);
            objectAnimator.setRepeatCount(Animation.RESTART); //重新开始播放动画
            objectAnimator.setRepeatCount(Animation.INFINITE);//循环播放动画
            objectAnimator.setDuration(10*1000);//设置动画时间为10秒
        }
        objectAnimator.setInterpolator(new LinearInterpolator());//设置线性插值器
        flyAnimatorSet.play(objectAnimator);
        animation.start();     //开启逐帧动画
        flyAnimatorSet.start();//开启属性动画
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CH10-图形图像处理 的相关文章

  • 网工我劝你,这11种协议报文格式要烂熟于心!

    你们好 我的网工朋友 你最熟悉的报文是啥 TCP UDP 在网络世界里 就如同道路系统让车辆畅通无阻一样 网络协议是确保信息顺畅传输的关键 作为网络工程师 理解网络协议的种类与结构至关重要 今天就和你一起探索一下11种关键协议报文格式啊 包
  • PDH光端机技术与应用:稳定可靠的数据传输解决方案

    在当今数字化 网络化日益加速的世界中 数据传输的稳定性和可靠性至关重要 PDH Plesiochronous Digital Hierarchy 准同步数字系列 光端机技术 作为早期的数字传输系统之一 虽然已被更先进的SDH Synchro
  • 网络安全现状:揭秘白帽黑客的真实收入

    前言 作为一个网络安全行业五年打工仔 今天就来看看黑客的收入和方向怎么样 一个黑客年薪是多少呢 外界普遍认为黑客是高收入群体 那么你想过黑客是怎么获得收入的吗 黑客分为白帽黑客和黑帽黑客 处于黑白两道的黑客会的技术都有些相似 但是却是对立的
  • 广告竞价策略:激发广告变现潜能的关键

    在数字化时代 广告已经成为企业推广品牌 产品和服务的关键手段之一 为了最大程度地发挥广告的效果 广告竞价策略成为广告主和数字营销专业人士关注的焦点 通过巧妙运用竞价策略 广告主可以在激烈的市场竞争中脱颖而出 实现广告变现的潜能 admaoy
  • HarmonyOS鸿蒙开发指南:容器组建 form开发指导

    目录 创建Form组件 实现表单缩放 设置Form样式 添加响应事件 场景示例 创建Form组件 在pages index目录下的hml文件中创建一个Form组件 div class container div
  • HarmonyOS鸿蒙开发指南:容器组建 stepper开发指导

    目录 创建Stepper组件 设置index属性 设置样式 添加事件 场景示例 创建Stepper组件 在pages index目录下的hml文件中创建一个Stepper组件 div class container div
  • HarmonyOS鸿蒙开发指南:容器组建 tabs开发指导

    目录 创建Tabs 设置Tabs方向 设置样式 显示页签索引 场景示例 创建Tabs 在pages index目录下的hml文件中创建一个Tabs组件 div class container div
  • 各大厂急招鸿蒙开发员,争抢鸿蒙工程师

    去年9月 余承东宣布鸿蒙原生应用全面启动 华为开始了全面抛弃安卓的进程 多家互联网公司也发布了鸿蒙OS的App开发工程师的岗位 开启了抢人大战 有的企业开出了近百万的年薪招聘鸿蒙OS工程师 而华为甚至为鸿蒙OS资深架构师开出了100万 16
  • OpenHarmony基于HDF简单驱动开发实例

    背景 OpenHarmony 3 0 LTS qemu small system demo liteos a qemu 添加配置 device qemu arm virt liteos a hdf config device info de
  • 白帽子如何快速挖到人生的第一个漏洞 | 购物站点挖掘商城漏洞

    本文针对人群 很多朋友们接触安全都是通过书籍 网上流传的PDF 亦或是通过论坛里的文章 但可能经过了这样一段时间的学习 了解了一些常见漏洞的原理之后 对于漏洞挖掘还不是很清楚 甚至不明白如何下手 可能你通过 sql labs 初步掌握了sq
  • 「网络安全渗透」如果你还不懂CSRF?这一篇让你彻底掌握

    1 什么是 CSRF 面试的时候的著名问题 谈一谈你对 CSRF 与 SSRF 区别的看法 这个问题 如果我们用非常通俗的语言讲的话 CSRF 更像是钓鱼的举动 是用户攻击用户的 而对于 SSRF 来说 是由服务器发出请求 用户 日 服务器
  • 【网安神器篇】——WPScan漏洞扫描工具

    目录 一 Wordpress简介 二 WPScan介绍 三 安装 四 获取token 1 注册账号 2 拿到token 五 使用教程 1 常用选项 2 组合命令 1 模糊扫描 2 指定扫描用户 3 插件漏洞扫描 4 主题漏洞扫描 5 Tim
  • HPE Aruba Networking:五大网络现代化策略助力实现校园数字化转型

    作者 Aruba中国区技术销售总监 俞世丹 全球数字化进程日益加深 科技已成为加速教育行业发展的重要驱动力 人工智能 大数据 云计算 物联网 虚拟现实等新兴技术的快速发展 正在深刻改变着教育的形态和模式 为了更好地满足学校师生个性化教育教学
  • 网络安全基础知识面试题库

    1 基于路由器的攻击手段 1 1 源IP地址欺骗式攻击 入侵者从外部传输一个伪装成来自内部主机的数据包 数据包的IP是 内网的合法IP 对策 丢弃所有来自路由器外端口 却使用内部源地址的数据包 1 2 源路由攻击 入侵者让数据包循着一个不可
  • HarmonyOS 基于eTS高效开发HarmonyOS课程类应用

    随着HarmonyOS 3 0 Beta版的发布 API Version 8新增了大批JS eTS API接口 相信很多开发者已经迫不及待想体验基于eTS的HamronyOS应用开发 本期Codelab 我们将基于API Version 8
  • 2024年华为OD机试真题-分割均衡字符串-Python-OD统一考试(C卷)

    题目描述 均衡串定义 字符串只包含两种字符 且两种字符的个数相同 给定一个均衡字符串 请给出可分割成新的均衡子串的最大个数 约定字符串中只包含大写的 X 和 Y 两种字符 输入描述 均衡串 XXYYXY 字符串的长度 2 10000 给定的
  • 为什么我强烈推荐大学生打CTF!

    前言 写这个文章是因为我很多粉丝都是学生 经常有人问 感觉大一第一个学期忙忙碌碌的过去了 啥都会一点 但是自己很难系统的学习到整个知识体系 很迷茫 想知道要如何高效学习 这篇文章我主要就围绕两点 减少那些罗里吧嗦的废话 直接上干货 CTF如
  • DSCA190V 57310001-PK

    DSCA190V 57310001 PK DSCA190V 57310001 PK 具有两个可编程继电器功能 并安装在坚固的 XP 外壳中 DSCA190V 57310001 PK 即可使用 只需最少的最终用户校准 DSCA190V 573
  • 【安全】简单解析统一身份认证:介绍、原理和实现方法

    深入解析统一身份认证 介绍 原理和实现方法 导语 统一身份认证是什么 统一身份认证的原理 统一身份认证的实现 结语 导语 随着互联网的发展和各种在线服务的普及 用户在不同的应用和平台上需要进行多次身份验证 为了简化用户的登录和减少重复操作
  • 2023下半年软考「单独划线」合格标准公布

    中国计算机技术职业资格网发布了 关于2023年度下半年计算机软件资格考试单独划线地区合格标准的通告 2023下半年软考单独划线地区合格标准各科目均为42分 01 官方通告 关于2023年度下半年计算机软件资格考试单独划线地区合格标准的通告

随机推荐

  • 滤波器相位补偿

    概要 滤波器使用的过程中都会产生相位的改变 有时 相位的改变并不是我们想要的 例如 笔者在做Dolby Atmos的bass management的时候 希望将顶置的低频成分分割到左右通道或环绕通道 因为相位的缘故 叠加之前 左右通道或环绕
  • windows

    1 准备工作 准备U盘 格式化U盘 注意选择格式化的文件系统 可以鼠标右键C盘查看 然后将U盘格式化 好像是跟电脑引导模式相关UEFI gt NTFS 如果格式化的时候没有选对文件系统 那么在BIOS界面可能无法识别到U盘 进入官网下载制作
  • 04_kibana 7.4.2 安装和配置指南

    本文大纲 1 Kibana 的下载方式 1 官网直接下载 2 Linux 服务器直接下载 需要能够访问互联网的服务器 2 修改配置 3 kibana 的关闭和重启 首先 值得高兴的是kibana7 x 已经有官方中文的啦 更加方便我们的开发
  • WebGL系列 - 裁剪空间矩阵优化

    该系列仅为记录自己的学习相关知识 以 2d 的顶点着色器为例
  • 模型评估相关参数学习

    training process loss accurancy val loss val accurancy testing process classification report label predict digits 8 labe
  • 【服务器】交换机带外管理和带内管理

    一 交换机的带外管理是什么 在带外管理模式中 网络的管理控制信息与用户网络的承载业务信息在不同的逻辑信道传送 带外管理最大的优势在于 当网络出现故障中断时数据传输和管理都可以正常进行 不同的物理通道传送管理控制信息和数据信息 两者完全独立
  • Activiti 学习(二)—— Activiti 流程定义和部署

    概述 在这一节 我们将创建一个 Activit 工作流 并启动这个流程 主要包含以下几个步骤 定义流程 按照 BPMN 的规范 使用流程定义工具 用流程符号把整个流程描述出来 部署流程 把画好的流程定义文件 加载到数据库中 生成表的数据 流
  • No module named 'numpy.core._multiarray_umath'

    导入tensorflow后遇到No module named numpy core multiarray umath 原因是numpy的当前版本过低 解决办法 更新numpy的版本 命令行输入 pip install i https pyp
  • java if oracle,JAVA使ORACLE 实现DROP TABLE IF EXISTS的功能

    JAVA使ORACLE 实现DROP TABLE IF EXISTS的功能 ORACLE没有MYSQL等数据库的DROP TABLE IF EXISTS 使用起来非常不便 删表还要求表必须存在 不存在则删表报错 太麻烦了 如果能实现其他数据
  • 学习Spring必学的Java基础知识(8)----国际化信息

    b size x large 引述 size b 要学习Spring框架的技术内幕 必须事先掌握一些基本的Java知识 正所谓 登高必自卑 涉远必自迩 以下几项Java知识和Spring框架息息相关 不可不学 我将通过一个系列分别介绍这些J
  • MySql 查询方法总结

    一 示例数据 dept表 emp表 二 查询方法 1 內连查询 a 隐式内连 select xxx from xxx where 条件 b 显示内连 select xxx from xxx inner jion xxx on 条件 2 外连
  • IDEA 接口方法不能跳转到实体类实现方法的问题

    IDEA 接口方法不能跳转到实体类实现方法的问题 问题描述 原因分析 解决方案 总结 问题描述 没有跳入到实体类实现方法的I 向下的箭头图标 原因分析 原因极大可能是因为编辑器自带的代码高亮工具 Syntaxhighlighte 失效 以下
  • 版本号对比 -- Python实现

    相同位数版本号大小比较 1 def abc str1 str2 2 if str1 or str2 3 print 输入包含空字符串 请重新输入 4 return 输入包含空字符串 请重新输入 5 elif str1 str2 6 prin
  • Unity3D项目输出到iOS设备体验

    很久以前就听说过这个软件个了 当时觉得有cocos2d就够用了 开发一般的手机游戏应该不成问题了 后来还学习了一下cocos3d 最近突然想看一下这个传说中的Unity3D 安装上之后 里边自带有一个demo 点了一下播放按键 发现这个de
  • 半监督结点分类

    3 半监督结点分类 我们已经介绍过了一个简单但是灵活的可在图上进行有效信息传播的模型f X A 现在我们可以回过头来看半监督结点分类的问题了 就像本文的介绍中所简要概述的那样 我们可以通过在数据集X和基础图结构的邻接矩阵A上调整来我们的模型
  • netty权威指南学习笔记二——netty入门应用

    经过了前面的NIO基础知识准备 我们已经对NIO有了较大了解 现在就进入netty的实际应用中来看看吧 重点体会整个过程 按照权威指南写程序的过程中 发现一些问题 当我们在定义handler继承ChannelHanderAdapter时候
  • linux脚本

    程序后台运行 nohup java jar xxx jar gt hello log 后台运行java jar命令 并且将日志输出到hello log文件 防火墙 开启防火墙 systemctl start firewalld 开放指定端口
  • 子组件多次复用且传参到父组件时遇到的一些问题。

    问题描述 我们都知道 父子组件之间传参用props 子向父用 emit 兄弟间有bus 但是今天遇到个问题 A组件是一个selector选择器小组件 根据传参不同选择项目也不同 返回结果也不同 B组件中使用了4次A组件 传参都不一样 且需要
  • H5页面中添加微信公众号关注链接

    用下面地址做个链接 点击就会跳转到公众号关注页面 点击关注按钮 就能直接关注 https mp weixin qq com mp profile ext action home biz 替换公众号uin base6 wechat redir
  • CH10-图形图像处理

    目标 掌握常用绘图类的使用 能够绘制不同的图形 掌握Matrix类的使用方式 能够实现为图片添加特效的功能 掌握动画的使用 能够实现补间动画与逐帧动画的效果 图形图像在Android应用中会经常用到 如一些程序的图标 界面的美化等都离不开图