android java 用系统弹窗的方式实现模拟点击动画特效

接上一篇:android java系统弹窗的基础模板-CSDN博客

本篇记录的是系统弹窗的一个应用示例:实现点击动画效果

首先模拟点击的实现参考:android模拟点击_motionevent upevent = motionevent.obtain(systemclo-CSDN博客

动画效果,是指点击之后,在点击的中心坐标,播放一个固定时长的动画。

因为需要能够在其他应用上播放动画,所以可以使用系统悬浮窗,即系统弹窗来实现。

实现上很多可参考android java系统弹窗的基础模板-CSDN博客

1、资源文件xml比模板更简单

app\src\main\res\layout\click_layout.xml

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">
	<ImageView
		android:id="@+id/clickImageView"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"/>
</LinearLayout>

因为只需要一个view,不需要其他ui控件,所以更简单

2、代码实现

2.1 初始化同模板

特意初始化了一下动画image的高度

rootView初始化,AddOrUpdateView我封装的用来添加rootView到windowManager的接口。rootView初始设置为隐藏。

java 复制代码
    private View rootView;
    private ImageView imageView;
    private Context farContext;
    private int imageHeight;    

    public void Init(Context context) {
        farContext = context;
        rootView = LayoutInflater.from(context).inflate(R.layout.click_layout, null);
        imageView = rootView.findViewById(R.id.clickImageView);

        imageHeight = ScreenResolutionReceiver.getResolutionHeight() / 20;

        AddOrUpdateView(rootView, 0, 0, true);
        rootView.setVisibility(View.GONE);
    }

2.2 AddOrUpdateView封装,方便复用

WindowManager.LayoutParams params设置悬浮窗的高度宽度为资源文件的初始高度宽度,且为叠加在上方形式overlay,背景为透明色(因为会加载动画,所以不需要背景色)。

用入参x、y动态调整悬浮窗的位置。 - imageHeight / 2保证悬浮窗的中心点是鼠标点击的坐标点。

java 复制代码
    private WindowManager windowManager;

    private void AddOrUpdateView(View view, int x, int y, boolean add) {
        windowManager = (WindowManager)farContext.getSystemService(WINDOW_SERVICE);

        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT, // 初始高度
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSPARENT);

        params.gravity = Gravity.LEFT | Gravity.TOP;
        params.x = x - imageHeight / 2;
        params.y = y - imageHeight / 2;

        if (add) {
            windowManager.addView(view, params);
        } else {
            windowManager.updateViewLayout(view, params);
        }
    }

2.3 加载gif动画,实现点击特效

使用了Glide来加载gif,glide组件,本身是需要在build.gradle的dependencies里添加下面两行:

java 复制代码
    implementation 'com.github.bumptech.glide:glide:4.12.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'

点击则触发播放1s的动画效果,要实现的逻辑如下:

弹窗设置为显示的同时,加载gif,执行一次动画效果就够了,然后设定为1s(经验值)后隐藏弹窗。

主要是超时这块比较难搞,尝试了几种写法都不好用。不断调整搜索的关键字,最终找到了handler msg.what的用法。

这块值得一说的是,使用AIGC来做件事的效率,不如使用搜索引擎。因为android开发的特点,就是方法过多过杂,不少方法都是过时、不完整的、甚至错误的。这也是和android本身历史版本过多有关,且有些网上文章给出的就是针对某些特殊硬件的。所以,这种情况下,AI大模型本身的训练数据可能就有些脏,往往也给不出好的方案。而且大模型的回答过于正规,增加了阅读、试错的时间成本呢。对于已经能够熟练使用搜索引擎的人来说,使用后者的效率高得多。

如下,在glide的listener(new RequestListener<GifDrawable>()里,先设置循环次数为1,再模拟发送一个空的延时消息。然后在handler的处理队列里,设置弹窗为隐藏。

java 复制代码
    private final int delaytime = 1000;
    private final int msgWhat = 1;  // 随便设置都可以

    @SuppressLint("HandlerLeak")
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == msgWhat) {
                rootView.setVisibility(View.GONE);
            }
        }
    };

    public void LoadGif(int x, int y) {
        AddOrUpdateView(rootView, x, y, false);

        rootView.setVisibility(View.VISIBLE);

        int resourceId = R.drawable.click_loading;
        new Handler(Looper.getMainLooper()).post(() -> {
                    Glide.with(getContext())
                            .asGif()
                            .load(resourceId)
                            .override(imageHeight, imageHeight) // 保持宽高比,限制高度
                            .diskCacheStrategy(DiskCacheStrategy.ALL)
                            .listener(new RequestListener<GifDrawable>() {
                                @Override
                                public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<GifDrawable> target, boolean isFirstResource) {
                                    return false;
                                }

                                @Override
                                public boolean onResourceReady(GifDrawable resource, Object model, Target<GifDrawable> target, DataSource dataSource, boolean isFirstResource) {
                                    resource.setLoopCount(1); // 设置循环次数为1

                                    //发送延时消息,通知动画结束
                                    //以下两个参数都是 int 型,记得如上的声明
                                    handler.sendEmptyMessageDelayed(msgWhat, delaytime);
                                    return false;
                                }
                            })
                            .into(imageView);
                }
        );
    }
相关推荐
雨白3 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹4 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空6 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭6 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日7 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安7 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑8 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟12 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡13 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0013 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体