Android开发实战《手机安全卫士》——7.“高级工具”模块结尾 & 小火箭动画

1.高级工具——Toast提示框的双击事件

上面的小节中我们完成了包括提示框的拖曳在内的基本功能,现在需要完善提示框的双击事件,使提示框在双击时处于居中位置。

要让控件相对于屏幕居中,需要进行相应计算,公式如图所示:
在这里插入图片描述

修改ToastLocationActivity,修改initUI(),完善提示框双击事件的业务逻辑。注意,为了让控件的setOnClickListenersetOnTouchListener两个监听器同时发挥效果,需要修改setOnTouchListener的返回值结果,即最终返回值需要为false,代码如下:

package com.example.mobilesafe.activity;

import android.app.Activity;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import com.example.mobilesafe.R;
import com.example.mobilesafe.constant.ConstantValue;
import com.example.mobilesafe.utils.SharedPreferencesUtil;


public class ToastLocationActivity extends Activity {

    private ImageView iv_drag;

    private Button btn_top;

    private Button btn_bottom;

    private int startX;

    private int startY;

    private WindowManager mWindowManager;

    private int mScreenHeight;

    private int mScreenWidth;

    // 存储点击事件的数组,数组容量就是点击次数
    private long[] mHits = new long[2];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_toast_location);

        // 初始化UI
        initUI();
    }

    /**
     * 初始化UI
     */
    private void initUI() {
        iv_drag = findViewById(R.id.iv_drag);
        btn_top = findViewById(R.id.btn_top);
        btn_bottom = findViewById(R.id.btn_bottom);

        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        mScreenHeight = mWindowManager.getDefaultDisplay().getHeight();
        mScreenWidth = mWindowManager.getDefaultDisplay().getWidth();

        // 从sp中读取的坐标值
        int locationX = SharedPreferencesUtil.getInt(getApplicationContext(), ConstantValue.LOCATION_X, 0);
        int locationY = SharedPreferencesUtil.getInt(getApplicationContext(), ConstantValue.LOCATION_Y, 0);

        // 左上角的坐标作用在iv_drag上,由于该控件在相对布局中,所以其所在位置的规则需要由相对布局提供
        RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); // 指定宽高
        layoutParams.leftMargin = locationX; // 配置左上角的X坐标
        layoutParams.topMargin = locationY; // 配置左上角的Y坐标

        // 将以上规则作用在iv_drag上
        iv_drag.setLayoutParams(layoutParams);

        if (locationY > mScreenHeight / 2){ // 移动到屏幕的下半部分
            btn_bottom.setVisibility(View.INVISIBLE);
            btn_top.setVisibility(View.VISIBLE);
        }else { // 移动到屏幕的上半部分
            btn_bottom.setVisibility(View.VISIBLE);
            btn_top.setVisibility(View.INVISIBLE);
        }

        // 监听某一个控件的双击事件
        iv_drag.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                System.arraycopy(mHits,1,mHits,0,mHits.length - 1);
                mHits[mHits.length - 1] = SystemClock.uptimeMillis();
                if (mHits[mHits.length - 1] - mHits[0] < 500){ // 两次点击间隔0.5秒
                    // 满足双击事件后的调用
                    int left = mScreenWidth / 2 - iv_drag.getWidth() / 2;
                    int top = mScreenHeight / 2 - iv_drag.getHeight() / 2;
                    int right = mScreenWidth / 2 + iv_drag.getWidth() / 2;
                    int bottom = mScreenHeight / 2 + iv_drag.getHeight() / 2;

                    // 控件按以上提供的四个坐标来显示
                    iv_drag.layout(left,top,right,bottom);

                    // 存储最终位置
                    SharedPreferencesUtil.putInt(getApplicationContext(), ConstantValue.LOCATION_X,iv_drag.getLeft());
                    SharedPreferencesUtil.putInt(getApplicationContext(), ConstantValue.LOCATION_Y,iv_drag.getTop());
                }
            }
        });

        // 监听某一个控件的拖拽过程(按下(1)、移动(多次)、抬起(1))
        iv_drag.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()){
                    case MotionEvent.ACTION_DOWN:
                        startX = (int) event.getRawX();
                        startY = (int) event.getRawY();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        int moveX = (int) event.getRawX();
                        int moveY = (int) event.getRawY();
                        int disX = moveX - startX;
                        int disY = moveY - startY;

                        // 1.获取当前控件所在屏幕的(左,上)角的位置
                        int left = iv_drag.getLeft() + disX; // 左侧坐标
                        int top = iv_drag.getTop() + disY; // 上侧坐标
                        int right = iv_drag.getRight() + disX; // 右侧坐标
                        int bottom = iv_drag.getBottom() + disY; // 下侧坐标

                        // 容错处理(iv_drag不能拖拽出手机屏幕)
                        if (left < 0){ // 左边缘不能超出屏幕
                            return true;
                        }
                        if (right > mScreenWidth){ // 右边缘不能超出屏幕
                            return true;
                        }
                        if (top < 0){ // 上边缘不能超出屏幕
                            return true;
                        }
                        if (bottom > mScreenHeight - 22){ // 下边缘(屏幕的高度 - 22 = 底边缘的显示最大值)不能超出屏幕
                            return true;
                        }

                        if (top > mScreenHeight / 2){ // 移动到屏幕的下半部分
                            btn_bottom.setVisibility(View.INVISIBLE);
                            btn_top.setVisibility(View.VISIBLE);
                        }else { // 移动到屏幕的上半部分
                            btn_bottom.setVisibility(View.VISIBLE);
                            btn_top.setVisibility(View.INVISIBLE);
                        }

                        // 2.告知移动的控件,根据计算出来的坐标去做展示
                        iv_drag.layout(left,top,right,bottom);

                        // 3.重置一次起始坐标
                        startX = (int) event.getRawX();
                        startY = (int) event.getRawY();
                        break;
                    case MotionEvent.ACTION_UP:
                        // 4.记录上次移动后的坐标位置
                        SharedPreferencesUtil.putInt(getApplicationContext(), ConstantValue.LOCATION_X,iv_drag.getLeft());
                        SharedPreferencesUtil.putInt(getApplicationContext(), ConstantValue.LOCATION_Y,iv_drag.getTop());
                        break;
                }
                // 在当前的情况下返回false表示不响应事件,返回true才表示响应事件
                // 既要响应点击事件,又要响应拖拽过程,则此返回值结果需要修改为false
                return false;
            }
        });
    }
}

根据以上代码,可以做出简单总结:

  1. 自定义的onTouch()方法返回了true,所以dispatchTouchEvent()直接返回了true,随后响应事件;
  2. 自定义的onTouch()方法返回了false,而控件设置过点击事件,所以具有点击事件,在手势抬起时,就会进行响应,即onClick(),然后dispatchTouchEvent()返回的也是true。

论证这段总结的dispatchTouchEvent()伪代码如图所示:

在这里插入图片描述

2.高级工具——服务中处理Toast提示框的拖拽事件

上一节中我们处理好了Toast提示框的位置处理信息,这一节需要将其与Service联动起来,即读取sp中存储的左上角坐标值即可。

修改AddressService,修改showToast()方法,读取sp中存储的左上角坐标,并且将值赋给自定义(ViewToast)控件即可。除此之外,为其注册触摸监听器,使其可以随意拖动,代码如下:

package com.example.mobilesafe.service;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;

import com.example.mobilesafe.R;
import com.example.mobilesafe.constant.ConstantValue;
import com.example.mobilesafe.dao.AddressDao;
import com.example.mobilesafe.utils.SharedPreferencesUtil;

public class AddressService extends Service {

    private TelephonyManager mSystemService;

    private MyPhoneStateListener mPhoneStateListener;

    // Layout对象
    private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();

    // 自定义的Toast布局
    private View mViewToast;

    // 获取窗体对象
    private WindowManager mWindowsManager;

    // 归属地信息
    private String mAddress;

    // 归属地信息显示控件
    private TextView tv_toast;

    // 存储资源图片id的数组
    private int[] mDrawableIds;

    // ViewToast的X坐标
    private int startX;

    // ViewToast的Y坐标
    private int startY;

    // 窗体的宽度
    private int mScreenWidth;

    // 窗体的高度
    private int mScreenHeight;

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            tv_toast.setText(mAddress);
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        // 第一次开启服务时,就需要管理Toast的显示
        // 同时,还需要监听电话的状态(服务开启时监听,关闭时电话状态就不需要监听了)

        // 1.电话管理者对象
        mSystemService = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

        mPhoneStateListener = new MyPhoneStateListener();

        // 2.监听电话状态
        mSystemService.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);

        // 5.获取窗体对象
        mWindowsManager = (WindowManager) getSystemService(WINDOW_SERVICE);

        mScreenHeight = mWindowsManager.getDefaultDisplay().getHeight();
        mScreenWidth = mWindowsManager.getDefaultDisplay().getWidth();
    }

    // 3.实现一个继承了PhoneStateListener的内部类
    class MyPhoneStateListener extends PhoneStateListener{
        // 4.手动重写,电话状态发生改变时会触发的方法
        @Override
        public void onCallStateChanged(int state, String phoneNumber) {
            super.onCallStateChanged(state, phoneNumber);
            switch (state){
                case TelephonyManager.CALL_STATE_IDLE:
                    // 空闲状态,没有任何活动,挂断电话时需要移除Toast
                    if (mWindowsManager != null && mViewToast != null){
                        mWindowsManager.removeView(mViewToast);
                    }
                    break;
                case TelephonyManager.CALL_STATE_OFFHOOK:
                    // 摘机状态,至少有个电话活动,该活动是拨打或者通话
                    break;
                case TelephonyManager.CALL_STATE_RINGING:
                    // 响铃状态
                    showToast(phoneNumber);
                    break;
            }
        }
    }

    /**
     * 打印Toast
     */
    private void showToast(String phoneNumber) {
        // 自定义Toast
        final WindowManager.LayoutParams params = mParams;
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
        params.format = PixelFormat.TRANSLUCENT;
        params.type = WindowManager.LayoutParams.TYPE_PHONE; // 在响铃的时候显示Toast,和电话类型一致
        params.gravity = Gravity.LEFT + Gravity.TOP; // 指定位置到左上角
        // 自定义了Toast的布局,需要将xml转换成view,将Toast挂到windowManager窗体上
        mViewToast = View.inflate(this, R.layout.toast_view, null);
        tv_toast = mViewToast.findViewById(R.id.tv_toast);

        mViewToast.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()){
                    case MotionEvent.ACTION_DOWN:
                        startX = (int) event.getRawX();
                        startY = (int) event.getRawY();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        int moveX = (int) event.getRawX();
                        int moveY = (int) event.getRawY();

                        int disX = moveX - startX;
                        int disY = moveY - startY;

                        // 赋值给自定义控件
                        params.x = params.x + disX;
                        params.y = params.y + disY;

                        // 容错处理
                        if (params.x < 0){
                            params.x = 0;
                        }
                        if (params.y < 0){
                            params.y = 0;
                        }
                        if (params.x > mScreenWidth - mViewToast.getWidth()){
                            params.x = mScreenWidth - mViewToast.getWidth();
                        }
                        if (params.y > mScreenHeight - mViewToast.getHeight() - 22){
                            params.y = mScreenHeight - mViewToast.getHeight() - 22;

                        }

                        // 根据手势移动,在窗体上去进行自定义控件位置的更新
                        mWindowsManager.updateViewLayout(mViewToast,params);

                        // 重置一次起始坐标
                        startX = (int) event.getRawX();
                        startY = (int) event.getRawY();
                        break;
                    case MotionEvent.ACTION_UP:
                        SharedPreferencesUtil.putInt(getApplicationContext(),ConstantValue.LOCATION_X,params.x);
                        SharedPreferencesUtil.putInt(getApplicationContext(),ConstantValue.LOCATION_Y,params.y);
                        break;
                }
                // 在当前的情况下返回false表示不响应事件,返回true才表示响应事件
                // 既要响应点击事件,又要响应拖拽过程,则此返回值结果需要修改为false
                return true;
            }
        });

        // 读取sp中存储Toast左上角坐标值(x,y)
        int localX = SharedPreferencesUtil.getInt(getApplicationContext(), ConstantValue.LOCATION_X, 0);
        int localY = SharedPreferencesUtil.getInt(getApplicationContext(), ConstantValue.LOCATION_Y, 0);

        // 将读取的坐标值赋给params(这里的坐标默认代表左上角)
        params.x = localX;
        params.y = localY;


        // 从sp中后去色值文字的索引,匹配图片,用作展示
        mDrawableIds = new int[]{R.drawable.function_greenbutton_normal,
                R.drawable.function_greenbutton_normal,
                R.drawable.function_greenbutton_normal,
                R.drawable.function_greenbutton_normal,
                R.drawable.function_greenbutton_normal};
        int toastStyle = SharedPreferencesUtil.getInt(getApplicationContext(), ConstantValue.TOAST_STYLE, 0);
        tv_toast.setBackgroundResource(mDrawableIds[toastStyle]);

        mWindowsManager.addView(mViewToast,params); // 在窗体上挂载View

        // 获取了来电号码以后,需要做来电号码查询
        query(phoneNumber);
    }

    private void query(final String phoneNumber){
        new Thread(){
            @Override
            public void run() {
                mAddress = AddressDao.getAddress(phoneNumber);
                mHandler.sendEmptyMessage(0);
            }
        }.start();
    }

    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 取消对电话状态的监听
        if (mSystemService != null && mPhoneStateListener != null){
            mSystemService.listen(mPhoneStateListener,PhoneStateListener.LISTEN_NONE);
        }
    }
}

3.拓展功能——小火箭需求分析

之前完成了设置中心里三个条目的功能——开启来电归属地信息显示、设置显示样式、设置显示位置。接下来我们需要完成另一个常见的功能——清理内存。清理内存一般都由一个小火箭的动画来实现,实现这个动画需要注意以下几点:

  1. 小火箭游离在Activity之外,和Activity的开启/关闭没有关系,说明需要写在Service中;
  2. 小火箭需要挂载在窗体上;
  3. 小火箭的“喷射火焰”动画由两张图片做轮训切换展示;
  4. 小火箭可以被拖拽;
  5. 小火箭拖拽到指定区域时,才可以被点击,然后触发“发射”动画;
  6. 小火箭在“发射”时具有“尾气”的动画。

由于该功能并非主要功能,是可以选择性添加的功能,所以这里就单独将其拿出来进行讲解。

4.拓展功能——小火箭的业务实现

在res/drawable下新建一个名为rocket_bg.xml的资源,表示这是小火箭在喷射时的动画,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- 第一张图片,火焰较短 -->
    <item android:drawable="@drawable/desktop_rocket_launch_1"
           android:duration="200"/>
    <!-- 第二张图片,火焰较长 -->
    <item android:drawable="@drawable/desktop_rocket_launch_2"
           android:duration="200"/>
</animation-list>

随后,在res/layout下新增名为rocket_view.xml的布局文件,代表小火箭的布局,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical" >
    
    <ImageView
        android:id="@+id/iv_rocket"
        android:background="@drawable/rocket_bg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

接下来,创建RocketService,作为小火箭开启和关闭时的Service,完善相应逻辑,注意在Service中开启Activity需要给intent设置一个参数,即FLAG_ACTIVITY_NEW_TASK代码如下:

package com.example.rocketman;

import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.ImageView;

public class RocketService extends Service {
	private WindowManager mWM;
	private int mScreenHeight;
	private int mScreenWidth;
	private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
	private View mRocketView;
	private Handler mHandler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			params.y = (Integer) msg.obj;
			//告知窗体更新火箭view的所在位置
			mWM.updateViewLayout(mRocketView, params);
		};
	};
			

	private WindowManager.LayoutParams params;	@Override
	public void onCreate() {
		//获取窗体对象
		mWM = (WindowManager) getSystemService(WINDOW_SERVICE);
		
		mScreenHeight = mWM.getDefaultDisplay().getHeight();
		mScreenWidth = mWM.getDefaultDisplay().getWidth();
		
		//开启火箭
		showRocket();
		super.onCreate();
	}
	private void showRocket() {
		params = mParams;
        params.height = WindowManager.LayoutParams.WRAP_CONTENT;
        params.width = WindowManager.LayoutParams.WRAP_CONTENT;
        params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
//                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE	默认能够被触摸
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
        params.format = PixelFormat.TRANSLUCENT;
        //在响铃的时候显示吐司,和电话类型一致
        params.type = WindowManager.LayoutParams.TYPE_PHONE;
        params.setTitle("Toast");
        
        //指定吐司的所在位置(将吐司指定在左上角)
        params.gravity = Gravity.LEFT+Gravity.TOP;
        
        //定义吐司所在的布局,并且将其转换成view对象,添加至窗体(权限)
        
        mRocketView = View.inflate(this, R.layout.rocket_view, null);
        
        ImageView iv_rocket = (ImageView) mRocketView.findViewById(R.id.iv_rocket);
        AnimationDrawable animationDrawable = (AnimationDrawable) iv_rocket.getBackground();
        animationDrawable.start();
        
        mWM.addView(mRocketView, params);
        
        mRocketView.setOnTouchListener(new OnTouchListener() {
			private int startX;
			private int startY;

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					startX = (int) event.getRawX();
					startY = (int) event.getRawY();
					break;
				case MotionEvent.ACTION_MOVE:
					int moveX = (int) event.getRawX();
					int moveY = (int) event.getRawY();
					
					int disX = moveX-startX;
					int disY = moveY-startY;
					
					params.x = params.x+disX;
					params.y = params.y+disY;
					
					//容错处理
					if(params.x<0){
						params.x = 0;
					}
					
					if(params.y<0){
						params.y=0;
					}
					
					if(params.x>mScreenWidth-mRocketView.getWidth()){
						params.x = mScreenWidth-mRocketView.getWidth();
					}
					
					if(params.y>mScreenHeight-mRocketView.getHeight()-22){
						params.y = mScreenHeight-mRocketView.getHeight()-22;
					}
					
					//告知窗体吐司需要按照手势的移动,去做位置的更新
					mWM.updateViewLayout(mRocketView, params);
					
					startX = (int) event.getRawX();
					startY = (int) event.getRawY();
					
					break;
				case MotionEvent.ACTION_UP:
					if(params.x>100 && params.x<200 && params.y>350){
						//发射火箭
						sendRocket();
						//开启产生尾气的activity
						Intent intent = new Intent(getApplicationContext(), BackgroundActivity.class);
						//开启火箭后,关闭了唯一的activity对应的任务栈,所以在此次需要告知新开启的activity开辟一个新的任务栈
						intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
						startActivity(intent);
					}
					break;
				}
				return true;
			}
		});
	}
	
	protected void sendRocket() {
		//在向上的移动过程中,一直去减少y轴的大小,直到减少为0为止
		//在主线程中不能去睡眠,可能会导致主线程阻塞
		new Thread(){
			public void run() {
				for(int i=0;i<11;i++){
					int height = 350-i*35;
					try {
						Thread.sleep(50);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					Message msg = Message.obtain();
					msg.obj = height;
					mHandler.sendMessage(msg);
				}
			};
		}.start();
		
		
	}
	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}
	@Override
	public void onDestroy() {
		if(mWM!=null && mRocketView!=null){
			mWM.removeView(mRocketView);
		}
		super.onDestroy();
	}
}

随后再新建一个名为BackgroundActivity的透明样式的Activity,作为小火箭产生喷射尾气的Activity。其布局文件和代码如下:

<?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" >
    <ImageView 
        android:id="@+id/iv_bottom"
        android:layout_alignParentBottom="true"
        android:background="@drawable/desktop_smoke_m"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <ImageView 
        android:id="@+id/iv_top"
        android:layout_above="@id/iv_bottom"
        android:background="@drawable/desktop_smoke_t"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</RelativeLayout>
package com.example.rocketman;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.animation.AlphaAnimation;
import android.widget.ImageView;

public class BackgroundActivity extends Activity {
	private Handler mHandler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			finish();
		};
	};
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_background);
		
		ImageView iv_top = (ImageView) findViewById(R.id.iv_top);
		ImageView iv_bottom = (ImageView) findViewById(R.id.iv_bottom);
		
		AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
		alphaAnimation.setDuration(500);
		iv_top.startAnimation(alphaAnimation);
		iv_bottom.startAnimation(alphaAnimation);
		
		mHandler.sendEmptyMessageDelayed(0, 1000);
	}
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赈川

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值