当前位置: 首页 > news >正文

可拖动、可靠边的 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);
});

相关文章:

  • 数据结构及八种常用数据结构简介
  • 使用软路由(openWrt)安装openVPN搭建局域网连接
  • 【C++】入门三
  • 机器学习与图像识别(二)—— OpenCV环境折腾。。
  • 【Linux】20、进程状态:不可中断进程、iowait、僵尸进程、dstat strace pstree
  • oracle-buffer cache
  • 华为模拟器dhcp实验
  • X3DAudio1_7.dll丢失原因,X3DAudio1_7.dll丢失怎样解决分享
  • 星火模型(Spark)的langchain 实现
  • TDengine 跨版本迁移实战
  • lambda表达式c++
  • php mysql 如何处理查询中存在正则特殊字符的查询
  • 十、Linux运行级别
  • 常见的SQL语句及函数
  • 线程的三种创建方式
  • 【React系列】如何构建React应用程序
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • JAVA 学习IO流
  • Javascript编码规范
  • JavaScript设计模式与开发实践系列之策略模式
  • Java应用性能调优
  • Js基础知识(四) - js运行原理与机制
  • mysql 5.6 原生Online DDL解析
  • React as a UI Runtime(五、列表)
  • React的组件模式
  • spring学习第二天
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 今年的LC3大会没了?
  • 理解在java “”i=i++;”所发生的事情
  • 聊聊hikari连接池的leakDetectionThreshold
  • 前端js -- this指向总结。
  • 如何编写一个可升级的智能合约
  • 深度学习在携程攻略社区的应用
  • 推荐一个React的管理后台框架
  • 微信公众号开发小记——5.python微信红包
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • 用 Swift 编写面向协议的视图
  • scrapy中间件源码分析及常用中间件大全
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (1)(1.19) TeraRanger One/EVO测距仪
  • (阿里云万网)-域名注册购买实名流程
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (附源码)ssm高校运动会管理系统 毕业设计 020419
  • (附源码)ssm考试题库管理系统 毕业设计 069043
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (篇九)MySQL常用内置函数
  • (数据结构)顺序表的定义
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (转)树状数组
  • .net core 6 集成和使用 mongodb
  • .net core MVC 通过 Filters 过滤器拦截请求及响应内容
  • .NET Framework与.NET Framework SDK有什么不同?
  • .NET 应用架构指导 V2 学习笔记(一) 软件架构的关键原则
  • .NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)
  • .NET/C# 项目如何优雅地设置条件编译符号?