zoukankan      html  css  js  c++  java
  • Android基础笔记(十)- 帧动画、补间动画具体解释、对话框

    帧动画

    帧动画非常easy,我们首先看一下Google官方解释This is a traditional animation in the sense that it is created with a sequence of different images

    意思表达的非常明了,一个传统的动画是由一组不同的图片组成的。帧动画,就像GIF图片,通过一系列Drawable依次显示来模拟动画的效果。

    创建一帧动画分为一下几步(支持4.0以上):
    ①在项目project下,创建res/drawable文件夹;

    ②创建一个以<animation-list>为根元素的xml文件,并在根节点以下,加入一组<item>结点,用来载入图片。

    <?xml version="1.0" encoding="utf-8"?>
    <animation-list xmlns:android="http://schemas.android.com/apk/res/android" 
        android:oneshot="false">
        <item android:drawable="@drawable/girl_1" android:duration="200" />
        <item android:drawable="@drawable/girl_2" android:duration="200" />
        <item android:drawable="@drawable/girl_3" android:duration="200" />
        <item android:drawable="@drawable/girl_4" android:duration="200" />
        <item android:drawable="@drawable/girl_5" android:duration="200" />
        <item android:drawable="@drawable/girl_6" android:duration="200" />
        <item android:drawable="@drawable/girl_7" android:duration="200" />
        <item android:drawable="@drawable/girl_8" android:duration="200" />
        <item android:drawable="@drawable/girl_9" android:duration="200" />
        <item android:drawable="@drawable/girl_10" android:duration="200" />
        <item android:drawable="@drawable/girl_11" android:duration="200" />
    </animation-list>
    ③将一组图片放置在res/drawable文件夹下

    ④在layout布局文件里,加入一个<ImageView> 并在代码中找到,而且设置相关的资源。

    // 找到ImageView控件
    ImageView iv = (ImageView) findViewById(R.id.iv);
    // 为IV设置背景资源
    iv.setBackgroundResource(R.drawable.girl);
    // 创建帧动画并開始
    AnimationDrawable rocketAnimation = (AnimationDrawable) iv.getBackground();
    rocketAnimation.start();

    补间动画(Tween Animation)

    补间动画的名称来源是flash,在做flash动画时,在两个关键帧中间须要做“补间动画”,才干实现图画的运动;插入补间动画后两个关键帧之间的插补帧是由计算机自己主动运算而得到的。

    先介绍一些关键的方法:
    Animation:
    ★ setDuration 设置动画的运行时间
    ★ setRepeatCount 设置动画的反复次数
    ★ setRepeatMode 指定反复的模式(如:反转)
    ★ setFillAfter 指示动画指定完毕之后控件的状态是否停留在动画停
    止的时候
    ★ setAnimationListener 设置动画的事件监听器
    ImageView:
    ★ startAnimation(Animation a) 让ImageView运行某动画
    补间动画分为(透明、旋转、缩放、位移)等四种:

    ①透明(Alpha),动画涉及到非常多操作,具体的凝视已经加入到代码中了

    // 1.0f代表全然不透明
    // 0.0f代表全然透明
    float fromAlpha = 1.0f;
    float toAlpha = 0.0f;
    AlphaAnimation aa = new AlphaAnimation(fromAlpha, toAlpha);
    
    // 动画的配置
    aa.setDuration(2 * 1000); // 动画持续多久
    aa.setFillAfter(true); // 设为true之后,界面会停留在动画播放完时的界面
    aa.setRepeatCount(1); // 设置动画反复的次数
    aa.setRepeatMode(Animation.RESTART); // 动画重新启动或逆转,默认值为重新启动动画
    
    // 启动动画
    iv.startAnimation(aa);

    ②旋转(roate),涉及到非常多概念,代码以下也会以图例解释的

    // 旋转的起始角度
    float fromDegrees = 0;
    // 旋转的目标角度
    float toDegrees = 360;
    
    // 旋转的X轴中心点类型
    // 分为三种类型:Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF,Animation.RELATIVE_TO_PARENT.
    // X轴的原点的类型(相对于自己而言还是相对于父容器而言)
    int pivotXType = Animation.RELATIVE_TO_SELF;
    
    // 旋转的X轴坐标的值,一般被指定为一个百分比数;1.0代表着100%
    // 開始伸缩时的X轴的原点(例:0.5就是指以图片宽度的二分之中的一个的位置作为X轴的原点)
    float pivotXValue = 0.0f;
    
    // Y轴的原点的类型
    int pivotYType = Animation.RELATIVE_TO_SELF;
    // 開始伸缩时的Y轴的原点
    float pivotYValue = 0.0f;
    
    /*
     *这里对pivotXValue和pivotYValue的值具体说明一下
     *在Android中的坐标轴Y轴向下是增张的,X轴向右是增长的;
     *pivotXValue在API中被说明为:旋转的X轴坐标的值,一般被指定为一个百分比数;1.0代表着100%
     *也就是说,当我们指定为0.0f时,代表作是图片的X轴的0点;当指定为0.5f时,代表图片的width/2的位置;当被指定为1.0f时,代表图片的width位置;
     */
    
    RotateAnimation ra = new RotateAnimation(fromDegrees, toDegrees, pivotXType, pivotXValue, pivotYType, pivotYValue);
    
    // 动画的配置
    ra.setDuration(2 * 1000); // 动画持续多久
    ra.setRepeatCount(1); // 设置动画反复的次数
    ra.setStartOffset(2 * 1000); // 设置动画启动时间的偏移量,简单来说就是多长时间后启动动画
    
    // 启动动画
    iv.startAnimation(ra);

    大家肯定会对pivotXValuepivotYValue非常困惑,pivot是中心点的意思,也就是代表旋转动画X轴的坐标和旋转动画Y轴的坐标,亲,请看图吧。

    我认为画的还是挺清晰的。

    ③缩放(scale)

    // 0.0f代表0点的位置;0.5f代表图片宽度的一半的位置;1.0f代表图片整个图片宽度的位置;2.0f代表整个图片宽度的2倍;
    
    // 水平方向比例尺的起始值
    float fromX = 0.0f;
    // 水平方向比例尺的终值
    float toX = 2.0f;
    
    // 垂直方向比例尺的起始值
    float fromY = 0.0f;
    // 垂直方向比例尺的终值
    float toY = 2.0f;
    
    // X轴的原点的类型(相对于自己而言还是相对于父容器而言)
    int pivotXType = Animation.RELATIVE_TO_SELF;
    // 開始伸缩时的X轴的原点(例:0.5就是指以图片宽度的二分之中的一个的位置作为X轴的原点)
    float pivotXValue = 0.0f;
    int pivotYType = Animation.RELATIVE_TO_SELF;
    float pivotYValue = 0.0f;
    ScaleAnimation sa = new ScaleAnimation(fromX, toX, fromY, toY, pivotXType, pivotXValue, pivotYType, pivotYValue);
    sa.setDuration(2 * 1000);
    
    // 整个动画会呈现,从左上角向右下加放大2倍
    iv.startAnimation(sa);

    图片示比例如以下:

    ④位移(translate),以下是位移的代码,參数非常多,可是不太好解释,所以还是用图片来说说明

    // 位移的x轴起始坐标的类型(相对于自己还是相对父容器)
    int fromXType = Animation.RELATIVE_TO_PARENT;
    // x轴起点
    float fromXValue = -0.5f;
    int toXType = Animation.RELATIVE_TO_PARENT;
    // X轴的终点
    float toXValue = 0.5f;
    
    int fromYType = Animation.RELATIVE_TO_PARENT;
    // Y轴的起始坐标
    float fromYValue = -0.5f;
    int toYType = Animation.RELATIVE_TO_PARENT;
    // Y轴的终点坐标
    float toYValue = 0.5f;
    
    TranslateAnimation ta = new TranslateAnimation(fromXType, fromXValue, toXType, toXValue, fromYType, fromYValue, toYType, toYValue);
    ta.setDuration(2 * 1000);
    
    iv.startAnimation(ta);

    位移示意图:

    我们能够看到,在位移中,屏幕中央是(0.0f,0.0f),左上角的坐标为(-0.5f,-0.5f),右下角为(0.5f,0.5f);当以上面的代码运行时,图片会从左上角平移到右下角。

    ⑤动画的集合;顾名思义,即使把很多动画对象,加入到AnimationSet的集合中,然后交给控件运行,运行动画顺序就是动画加入的顺序。代码例如以下:

    AnimationSet set = new AnimationSet(false);
    
       ScaleAnimation  sa = new ScaleAnimation(0.1f, 2.0f, 0.1f, 2.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    
    sa.setDuration(3000); //设置动画的时间
    sa.setRepeatCount(1); //设置动画的显示次数 
    sa.setRepeatMode(AlphaAnimation.REVERSE);//设置播放模式
    
          RotateAnimation ra = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    
    ra.setDuration(3000); //设置动画的时间
    ra.setRepeatCount(1); //设置动画的显示次数 
    ra.setRepeatMode(AlphaAnimation.REVERSE);//设置播放模式
    
    
    TranslateAnimation ta = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, -0.5f, Animation.RELATIVE_TO_PARENT, 0.5f, Animation.RELATIVE_TO_PARENT, -0.5f, Animation.RELATIVE_TO_PARENT, 0.5f);
    ta.setDuration(3000); //设置动画的时间
    ta.setRepeatCount(1); //设置动画的显示次数 
    ta.setRepeatMode(AlphaAnimation.REVERSE);//设置播放模式
    
    set.addAnimation(sa);
    set.addAnimation(ta);
    set.addAnimation(ra);
    
    //播放动画 
    iv_icon.startAnimation(set);
    ⑤ 对于补间动画,它仅仅是改变了View对象绘制的位置,而没有改变View对象本身。

    对话框以及面试中的注意点

    Android中经常使用的对话框有通知对话框、列表对话框、单选对话框、多选对话框以及进度对话框。当中,通知对话框、列表对话框、单选、多选对话框由AlertDialog.Builder创建,进度对话框由ProgressDialog创建。

    经常使用的方法:
    ①setIcon:设置对话框标题栏左側的那个图标
    ②setTitle:设置对话框标题栏的提示信息
    ③setMessage:设置对话框主体部分的提示信息
    ④setPositiveButton:设置确定button
    ⑤setNegativeButton:设置取消button
    ⑥setCancelable:设置对话框在点击返回键时是否会关闭
    ⑦show:显示对话框
    getApplicationContext()MainActivity.this的差别:
    ①对于getApplicationContext(),我们能够从API看到这样一句话Return the context of the single, global Application object of the current process.,意思是:返回当前进程的一个单例的全局应用程序上下文对象,它代表的是Android系统中这个应用本身。
    ②对于MainActivity.this,代表的是一个具体的Activity对象;当我们在使用对话框时,它须要被绑定在某一个具体的界面上,因此也就不能够使用getApplicationContext()作为Context传入到构造函数中。
    ③当我们在对话框中传入getApplicationContext()时,会报一个异常:Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
    通知对话框

    通知对话框使用Builder创建,一般都会有个确认和取消button。当通知对话框提示的信息是要求用户必须观看且必须做出确定或者取消的选择的时候,须要设置setCancelable属性为false(默认true),以防止用户直接使用返回键关闭对话框。

    Builder builder = new Builder(this);
    builder.setIcon(R.drawable.ic_launcher);
    builder.setTitle("通知");
    builder.setMessage("您看到的是通知对话框!");
    //设置对话框点击返回键不关闭
    builder.setCancelable(false);
    //设置确定button的点击事件
    builder.setPositiveButton("确定", new OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            Toast.makeText(MainActivity.this, "您点击了确定button!", 0).show();
        }
    });
    //设置取消button的点击事件
    builder.setNegativeButton("取消", new OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            Toast.makeText(MainActivity.this, "您点击了取消button!", 0).show();
        }
    });
    //将对话框显示出来
    builder.show();
    
    列表对话框

    列表对话框使用Builder来创建,仅仅需调用Builder对象的setItems方法设置要展示的列表项就可以。

    Builder builder = new Builder(this);
    builder.setIcon(R.drawable.ic_launcher);
    builder.setTitle("请选择要去的城市");
    final String[] cities = new String[]{"北京","上海","广州","深圳","杭州"};
    builder.setItems(cities, new OnClickListener() {
        /*
         * 第一个參数代表对话框对象
         * 第二个參数是点击对象的索引
         */
        @Override
        public void onClick(DialogInterface dialog, int which) {
            String city = cities[which];
            Toast.makeText(MainActivity.this, "您选择的是:"+city, 0).show();
        }
    });
    builder.show();
    普通对话框

    还是比較简单的,涉及到了AlertDialog.Builder和一些方法,请看一下代码和凝视吧。

    // 创建一个对话框,并打算在`MainActivity`界面上展示
    Builder builder = new AlertDialog.Builder(MainActivity.this);
    
    // 设置标题和内容
    builder.setTitle("我是普通对话框标题");
    builder.setMessage("我是普通对话框内容");
    
    // 设置确定和取消button
    builder.setPositiveButton("我是确定button", new OnClickListener() {
    
        @Override
        public void onClick(DialogInterface dialog, int which) {
            Toast.makeText(getApplicationContext(), "确定button被点击了", Toast.LENGTH_SHORT).show();
            // 隐藏对话框
            dialog.dismiss();
        }
    });
    builder.setNegativeButton("我是取消button",  new OnClickListener() {
    
        @Override
        public void onClick(DialogInterface dialog, int which) {
            Toast.makeText(getApplicationContext(), "取消button被点击了", Toast.LENGTH_SHORT).show();
            // 隐藏对话框
            dialog.dismiss();
        }
    });
    
    // 显示对话框
    builder.show();
    单选对话框

    也是非常easy,与普通对话框相比,它不能够设置setMessage(),须要使用setSingleItemChoiceItems()方法。

    Builder builder = new AlertDialog.Builder(MainActivity.this);
    
    // 设置标题和内容
    builder.setTitle("我是普通对话框标题");
    
    // 单选对话框
    // 要展示的单选选项列表
    final String[] items = { "你是二货", "我是二货", "大家都是二货" };
    // 默认选中项的索引
    int checkedItem = 0;
    // 选中选项触发的点击事件
    OnClickListener listener = new OnClickListener() {
    
        @Override
        public void onClick(DialogInterface dialog, int which) {
            String res = items[which];
            Toast.makeText(getApplicationContext(), res, Toast.LENGTH_SHORT).show();
            dialog.dismiss();
        }
    };
    builder.setSingleChoiceItems(items, checkedItem, listener);
    
    // 显示对话框
    builder.show();
    多选对话框

    多选对话框使用Builder来创建,仅仅需调用Builder对象的setMultiChoiceItems方法,设置要展示的列表项就可以。

    Builder builder = new AlertDialog.Builder(MainActivity.this);
    
    // 设置标题和内容
    builder.setTitle("我是多选对话框标题");
    
    // 要展示的多选列表项
    final String[] items = { "你是二货", "我是二货", "大家都是二货" };
    // 相应每一个列表项的选中状态
    final boolean[] checkedItems = { false, false, false };
    // 设置点击事件
    OnMultiChoiceClickListener listener = new OnMultiChoiceClickListener() {
    
        @Override
        public void onClick(DialogInterface dialog, int which, boolean isChecked) {
            // 改动被选中的条目
            checkedItems[which] = isChecked;
        }
    };
    builder.setMultiChoiceItems(items, checkedItems, listener);
    
    // 设置确定和取消button
    builder.setPositiveButton("我是确定button", new OnClickListener() {
    
        @Override
        public void onClick(DialogInterface dialog, int which) {
    
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < checkedItems.length; i++) {
                if (checkedItems[i]) {
                    sb.append(items[i] + ",");
                }
            }
    
            Toast.makeText(getApplicationContext(), sb.toString(), Toast.LENGTH_SHORT).show();
            // 隐藏对话框
            dialog.dismiss();
        }
    });
    
    // 显示对话框
    builder.show();
    进度对话框

    进度对话框不同于之前几种对话框,它是由ProgressDialog对象来创建的,而且进度对话框内部使用了消息机制Handler来进行处理,所以它能够直接在子线程中进行改动,无需再单独设置Handler来改动UI。

    final ProgressDialog dialog = new ProgressDialog(MainActivity.this);
    
    // 设置图标
    dialog.setIcon(R.drawable.ic_launcher);
    dialog.setTitle("进度对话框");
    dialog.setMessage("玩命载入中...");
    // 设置对话框的样式为水平
    dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    // 设置进度条的最大值
    dialog.setMax(100);
    // 显示对话框
    dialog.show();
    
    new Thread() {
        public void run() {
            while (true) {
                // 休眠500ms
                SystemClock.sleep(500);
                // 进度条每次添加一个单位
                dialog.incrementProgressBy(1);
                // 进度条到头是退出
                if (dialog.getMax() == dialog.getProgress()) {
                    dialog.dismiss();
                    Toast.makeText(MainActivity.this, "下载完毕!", 0).show();
                }
            }
        };
    }.start();
    状态栏通知

    新版本号API的通知代码

    // 通知管理器
    NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    Notification noti = new Notification.Builder(this)//
            .setContentTitle("通知栏标题")//
            .setContentText("通知栏内容")//
            .setSmallIcon(R.drawable.ic_launcher)//
            .setAutoCancel(true)//
            .build();
    notificationManager.notify(0, noti);

    旧版本号的通知:

    // 通知管理器
    Notification n = new Notification(R.drawable.feq, "下载完毕", System.currentTimeMillis());
    // 创建PendingIntent以供点击时发送,延迟意图,点击时发送
    PendingIntent pi = PendingIntent.getActivity(this, 100,  new Intent(this, ResultActivity.class), PendingIntent.FLAG_ONE_SHOT);
    // 设置通知点击事件
    n.setLatestEventInfo(this, "下载完毕", "FeiQ.exe下载完毕", pi);
    // 设置通知点击后清除
    n.flags = Notification.FLAG_AUTO_CANCEL;
    // 获取系统通知服务
    NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    // 发送消息
    manager.notify(0, n);
    
    自己定义对话框步骤
    ①创建对话框构建器
    ②创建出一个空的对话框
    ③实例化自己定义布局
    ④给对话框设置自己定义布局
    ⑤给button设置点击事件
    自己定义布局的代码

    測试结果是:

    <?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="vertical" >
    
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入账号" />
    
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入password" />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal" >
    
            <Button
                android:id="@+id/btn_login"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="登陆" />
    
    
            <Button
                 android:id="@+id/btn_cancel"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="取消" />
        </LinearLayout>
    
    </LinearLayout>

    创建自己定义对话框的代码是:

    // 对话框构建器
    Builder builder = new AlertDialog.Builder(this);
    
    // 创建出一个空的对话框
    final AlertDialog dialog = builder.create();
    
    // 载入自己定义View布局
    View view = View.inflate(this, R.layout.custom_dialog, null);
    int viewSpacingLeft = 0;
    int viewSpacingTop = 0;
    int viewSpacingRight = 0;
    int viewSpacingBottom = 0;
    
    // 给对话框指定自己定义的layout文件,而且上下左右边框为0:不然对话框会出现黑框,由于低版本号的对话框,不指定背景的话就是黑色的。
    dialog.setView(view, viewSpacingLeft, viewSpacingTop, viewSpacingRight, viewSpacingBottom);
    
    // 找到button,设置点击事件
    Button btn_login = (Button) view.findViewById(R.id.btn_login);
    Button btn_cancel = (Button) view.findViewById(R.id.btn_cancel);
    btn_login.setOnClickListener(new View.OnClickListener() {
    
        @Override
        public void onClick(View v) {
            Toast.makeText(getApplicationContext(), "确定button被点击了", Toast.LENGTH_SHORT).show();
            dialog.dismiss();
        }
    });
    btn_cancel.setOnClickListener(new View.OnClickListener() {
    
        @Override
        public void onClick(View v) {
            Toast.makeText(getApplicationContext(), "取消button被点击了", Toast.LENGTH_SHORT).show();
            dialog.dismiss();
        }
    });
    
    // 显示对话框
    dialog.show();

    ★★★结合工作和面试★★★

    一个对话框弹出,Activity会运行什么生命周期方法?
    Activity不会运行不论什么方法
    怎样解决Toast反复弹出问题?这个工作中也会碰到这种需求。
    在我们做项目时,有时会用到Toast来给用户提示某些信息,可当用户视而不见时,连续反复的操作就会让Toast不停的在页面上显示,非常是影响用户体验。

    解决思路:不用计算Toast的时间之类的,就是定义一个全局的成员变量Toast, 这个Toast不为null的时候才去make,否则直接setText.为了按返回键后马上使Toast不再显示,重写父类Activity的 onBackPressed()方法里面去cancel你的Toast就可以.

    private Toast mToast;
    
    public void showToast(String text) {
    
        if (mToast == null) {
            mToast = Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT);
        } else {
            mToast.setText(text);
            mToast.setDuration(Toast.LENGTH_SHORT);
        }
        mToast.show();
    }
    
    public void cancelToast() {
        if (mToast != null) {
            mToast.cancel();
        }
    }
    
    public void onBackPressed() {
        cancelToast();
        super.onBackPressed();
    }
    
  • 相关阅读:
    静态文件
    orm多表操作
    thinkphp5.0模块设计
    thinkphp5.0URL访问
    thinkphp5.0入口文件
    thinkphp5.0生命周期
    thinkphp5.0架构总览
    thinkphp5.0目录结构
    thinkphp5.0开发规范
    thinkphp5.0安装
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4377911.html
Copyright © 2011-2022 走看看