可拖动、可靠边的 popupWindow 实现

0 背景

  开发要实现一个可以拖动的圆角小窗,要求松手时,哪边近些靠哪边。并且还规定了拖动范围。样式如下:
在这里插入图片描述

1 实现

首先把 PopupWindow 的布局文件 pop.xml 实现

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="88dp"android:layout_height="132dp"android:background="@drawable/radius_12"android:id="@+id/mini_popup"android:visibility="visible"><com.google.android.material.imageview.ShapeableImageViewandroid:id="@+id/iv_live_cover"android:layout_width="88dp"android:scaleType="fitXY"android:layout_height="132dp"android:background="@color/purple_200"app:shapeAppearanceOverlay="@style/MiniDialogRoundedImageStyle" /><ImageViewandroid:id="@+id/iv_close"android:layout_width="16dp"android:layout_height="16dp"android:layout_alignParentRight="true"android:layout_marginTop="4dp"android:layout_marginRight="4dp"android:src="@color/teal_200" />
</RelativeLayout>

布局中圆角和 PopupWindow 的动画 style.xml

    <!-- 圆角图片 --><style name="MiniDialogRoundedImageStyle"><item name="cornerFamily">rounded</item><item name="cornerSize">12dp</item></style><!-- PopupWindow 的动画效果 --><style name="PopupWindowAnimation"><item name="android:windowEnterAnimation">@anim/live_popup_window_in_anim</item></style>

radius_12.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><corners android:radius="12dp"/><solid android:color="@color/white"/>
</shape>

MyPopupWindow.java

package com.example.myapplication.popupwindow;import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.PopupWindow;import com.bumptech.glide.Glide;
import com.example.myapplication.R;public class MyPopupWindow extends PopupWindow {private Context mContext;private View mRootView;// 背景private ImageView mBackground;// 关闭弹窗private ImageView mIvClose;// 弹窗的移动范围private int mMinX;private int mMinY;private int mMaxX;private int mMaxY;// 屏幕宽高private int mScreenWidth;public MyPopupWindow(Context context) {super(context);mContext = context;mRootView = View.inflate(mContext, R.layout.pop, null);mScreenWidth = getScreenWidth(mContext);mMinX = dp2px(12);mMaxX = mScreenWidth - dp2px(12) - dp2px(88);mMinY = dp2px(12);mMaxY = dp2px(500);// 为了保证整体是圆角形状mRootView.findViewById(R.id.mini_popup).setClipToOutline(true);initView();}private void initView() {setContentView(mRootView);mBackground = mRootView.findViewById(R.id.iv_live_cover);mIvClose = mRootView.findViewById(R.id.iv_close);mIvClose.setOnClickListener(view -> this.dismiss());// 小窗的宽高setHeight(dp2px(132));setWidth(dp2px(88));this.setTouchInterceptor(new View.OnTouchListener() {int orgX, orgY;int offsetX, offsetY;@Overridepublic boolean onTouch(View view, MotionEvent motionEvent) {switch (motionEvent.getAction()) {case MotionEvent.ACTION_DOWN:orgX = (int) motionEvent.getX();orgY = (int) motionEvent.getY();break;case MotionEvent.ACTION_MOVE:offsetX = (int) motionEvent.getRawX() - orgX;offsetY = (int) motionEvent.getRawY() - orgY;// 限制 x 坐标offsetX = Math.max(offsetX, mMinX);offsetX = Math.min(offsetX, mMaxX);// 限制 y 坐标offsetY = Math.max(offsetY, mMinY);offsetY = Math.min(offsetY, mMaxY);update(offsetX, offsetY, -1, -1, true);break;case MotionEvent.ACTION_UP:// 小窗靠边if (offsetX < mScreenWidth / 2) {offsetX = mMinX;} else {offsetX = mMaxX;}update(offsetX, offsetY, -1, -1, true);break;}// 避免 view 中的其他点击事件被吞掉return false;}});// 设置小窗背景this.setBackgroundDrawable(mContext.getResources().getDrawable(R.drawable.abc_vector_test));// 出现的动画this.setAnimationStyle(R.style.PopupWindowAnimation);}public void show(View anchor) {this.showAtLocation(anchor, Gravity.NO_GRAVITY, mMaxX, mMaxY);}@SuppressLint("CheckResult")public void setBackground(String url) {if (url != null && !TextUtils.isEmpty(url))Glide.with(mContext).load(url).into(mBackground);}public int dp2px(float dpValue) {return (int) (0.5f + dpValue * Resources.getSystem().getDisplayMetrics().density);}public int getScreenWidth(Context context) {DisplayMetrics localDisplayMetrics = new DisplayMetrics();((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(localDisplayMetrics);return localDisplayMetrics.widthPixels;}
}

最后在 MainActivity 中使用

mTextView = findViewById(R.id.myView);
if (mMyPopupWindow == null) {mMyPopupWindow = new MyPopupWindow(MainActivity.this);
}
mTextView.post(() -> {mMyPopupWindow.show(mTextView);
});

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/148237.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

抽象工厂模式-C++实现

抽象工厂模式是一种创建型设计模式&#xff0c;它提供了一种在不指定具体产品类的情况下创建一系列相关或依赖对象的方法。 抽象工厂模式分为四个角色&#xff1a;抽象工厂、具体工厂、抽象产品、具体产品。 抽象工厂和工厂方法其实很类似&#xff0c;但也有一定的区别&#…

7.22 SpringBoot项目实战【收藏 和 取消收藏】

文章目录 前言一、编写控制器二、编写服务层三、Postman测试最后前言 本系统还支持 收藏图书,就是对心仪的书加一下收藏,大家都懂,这是一个很常见的功能。 那么我们来看看怎么来做,先分析一下:【一个人】对【一本书】只需【收藏一次】,但可以【收藏N本】不同的书,收藏…

【Java并发编程六】多线程越界问题

ArrayList()越界错误 import java.util.ArrayList; public class myTest implements Runnable {static ArrayList<Integer> a new ArrayList<>(10);public static void main(String[] args) throws InterruptedException {Thread t1 new Thread(new myTest());T…

Mac M1 M1 pro安装 protobuf 2.5.0

因为项目中的protobuf是2.5.0版本&#xff0c;但是旧版本的protobuf 不支持M1&#xff0c;此时需要修改源码重新编译 操作步骤&#xff1a; 从git上面下载对应版本的protobuf&#xff0c;地址&#xff1a;Release Protocol Buffers v2.5.0 protocolbuffers/protobuf GitHub…

深度学习之基于YoloV5苹果新鲜程度检测识别系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 深度学习之基于 YOLOv5 苹果新鲜程度检测识别系统介绍YOLOv5 简介苹果新鲜程度检测系统系统架构应用场景 二、功能三、系统四. 总结 一项目简介 深度学习之…

三十一、W5100S/W5500+RP2040树莓派Pico<TCP_Server多路socket>

文章目录 1 前言2 简介2. 1 使用多路socket的优点2.2 多路socket数据交互原理2.3 多路socket应用场景 3 WIZnet以太网芯片4 多路socket设置示例概述以及使用4.1 流程图4.2 准备工作核心4.3 连接方式4.4 主要代码概述4.5 结果演示 5 注意事项6 相关链接 1 前言 W5100S/W5500是一…

c#字符串

字符串比较 namespace demo1 {internal class progrm{static void Main(string[] args){string str "hello world";Console.WriteLine("大写字符{0}",str.ToUpper());Console.WriteLine("小写字符{0}",str.ToLower());Console.WriteLine("…

GitHub如何删除仓库

GitHub如何删除仓库 删除方法第一步第二步第三步 删除方法 第一步 在仓库的界面选择Settings 第二步 选择General,页面拉到最后。 第三步 删除仓库。

C++ 虚函数和多态性

虚函数和多态性 派生类中与基类重名的成员 如果派生类的成员与基类的成员重名&#xff0c;则派生类的成员将隐藏同名的基类成员。 /*正方形类&#xff0c;基类*/ class Square { protected:double L; public:Square() :L{ 4 } {};Square(double a) :L{ a } {}double GetArea…

C#密封类、偏类

C#密封类 在C#中&#xff0c;密封类&#xff08;Sealed Class&#xff09;是一种特殊的类&#xff0c;它阻止其他类继承它。你可以通过在类定义前面加上 sealed 关键字来创建一个密封类。 以下是一个密封类的例子&#xff1a; public sealed class MyClass {// Class member…

【Redis】zset常用命令集合间操作内部编码使用场景

文章目录 前置知识列表、集合、有序集合三者的异同点 普通命令ZADDZCARDZCOUNTZRANGEZREVRANGEZRANGEBYSCOREZPOPMAXBZPOPMAXZPOPMINBZPOPMINZRANKZREVRANKZSCOREZREMZREMRANGEBYRANKZREMRANGEBYSCOREZINCRBY 集合之间的操作ZINTERSTOREZUNIONSTORE 命令小结内部编码测试内部编…

PyTorch 成功安装验证

一、确认PyTorch版本 安装PyTorch之后&#xff0c;可以运行以下代码来确认PyTorch的版本&#xff1a; import torchprint(torch.__version__)如果没有报错&#xff0c;同时输出了正确版本号&#xff0c;就说明PyTorch已经成功安装了。 二、测试PyTorch基础功能 为了确保PyT…

C/C++---------------LeetCode第LCR. 024.反转链表

反转链表 题目及要求双指针 题目及要求 双指针 思路&#xff1a;遍历链表&#xff0c;并在访问各节点时修改 next 引用指向&#xff0c;首先&#xff0c;检查链表是否为空或者只有一个节点&#xff0c;如果是的话直接返回原始的头节点&#xff0c;然后使用三个指针来迭代整个…

DHCP配置命令

排除IP地址或IP范围&#xff08;保留&#xff09;&#xff1a; Switch(config)#ip dhcp excluded-address 192.168.10.1 192.168.10.10 为地址池取名&#xff1a; Switch(config)#ip dhcp pool name 分配地址范围&#xff1a; Switch(dhcp-config)#network 192.168.10.0 2…

windows 安装 Oracle Database 19c

目录 什么是 Oracle 数据库 下载 Oracle 数据库 解压文件 运行安装程序 测试连接 什么是 Oracle 数据库 Oracle数据库是由美国Oracle Corporation&#xff08;甲骨文公司&#xff09;开发和提供的一种关系型数据库管理系统&#xff0c;它是一种强大的关系型数据库管理系统…

lambda表达式c++

介绍 可调用对象 对于一个表达式&#xff0c;如果可以对其使用调用运算符&#xff08;&#xff09;&#xff0c;则称它为可调用对象。如函数就是一个可调用对象&#xff0c;当我们定义了一个函数f(int)时&#xff0c;我们可以通过f(5)来调用它。 可调用对象有&#xff1a; …

c语言中*p1++和p1++有啥区别

在C语言中&#xff0c;*p1和p1是两个不同的表达式&#xff0c;有以下区别&#xff1a; *p1&#xff1a;这是一个后缀递增运算符的组合。首先&#xff0c;*p1会取出指针p1所指向的值&#xff0c;并且对p1进行递增操作。简而言之&#xff0c;这个表达式会先取出p1指向的值&#x…

43-设计问题-最小栈

原题链接&#xff1a; 198. 打家劫舍 题目描述&#xff1a; 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&a…

基于springboot实现校园在线拍卖系统项目【项目源码】计算机毕业设计

基于springboot实现校园在线拍卖系统演示 Javar技术 JavaScript是一种网络脚本语言&#xff0c;广泛运用于web应用开发&#xff0c;可以用来添加网页的格式动态效果&#xff0c;该语言不用进行预编译就直接运行&#xff0c;可以直接嵌入HTML语言中&#xff0c;写成js语言&…

Java多线程核心技术第一阶段-Java多线程基础 02

接上篇&#xff1a;Java多线程核心技术第一阶段-Java多线程基础 01 3.3 清除中断状态的使用场景 this.interrupted()方法具有清除状态标志值的功能&#xff0c;借用此特性可以实现一些效果。 【示例3.3.1】在MyThread4线程中向list1和list2存放数据&#xff0c;基于单一职责原…