Android 通用带箭头提示窗

简介

自定义PopupWindow, 适用于提示类弹窗。

使用自定义Drawable设置带箭头的背景,测试控件和弹窗的尺寸,自动设置弹窗的显示位置,让箭头指向锚点控件的中间位置,且根据锚点控件在屏幕的位置,自动适配弹窗显示位置。 

适用于描述、解释弹窗。

一、效果

带箭头弹窗显示在控件的左侧,箭头相对控件居中对齐 ,且与控件左边框挨着

 示例代码如下:

二、使用

        GuZhiExplainPupopWindow window = new GuZhiExplainPupopWindow(this);//设置弹窗显示文案window.setTips("1234567890-34567890-【qweqwertyuiop[sdfghjkl;zxcvbnm,.我们一起走向富强");//获取窗口的背景drawable对象ArrowsDrawable ad = window.getArrowsDrawable();//设置drawable箭头的大小ad.setArrowsHeight(ConvertUtils.dp2px(8));//设置drawable中箭头与边框距离ad.setArrowsPadding(ConvertUtils.dp2px(10));//设置drawable的padding, 实际是设置显示文案的TextView的padding//ad.setPadding(ConvertUtils.dp2px(10));window.setPadding(ConvertUtils.dp2px(10));//设置drawable背景色ad.setColor(Color.DKGRAY);findViewById(R.id.tv33).setOnClickListener(view -> {if (!window.isShowing()) {//设置窗口显示位置(AUTO_HORIZONTAL 是水平位置,在控件的左侧或右侧,根据控件中心在屏幕中的位置决定)window.setShowPosition(GuZhiExplainPupopWindow.AUTO_HORIZONTAL);//显示弹窗,偏移量是0,默认是箭头在控件居中位置window.show(view, 0, 0);}});

三、自定义布局

重写initView方法,并设置TipsTv, 同时需要注意的是,在设置弹窗布局时,根布局的宽高属性是wrap_content,设置其它是不生效的,如果需要指定textView的宽或高,或弹窗尺寸,根布局使用某ViewGroup控件,再设置其子控件的尺寸。

        GuZhiExplainPupopWindow window = new GuZhiExplainPupopWindow(this, R.layout.pupopwindow_view_guzhi_explain) {@Overridepublic void initView(View contentView) {//自定义布局初始化控件super.initView(contentView);TextView customTv = contentView.findViewById(R.id.explain_tv);setTipsTv(customTv);}};

四、源码

package com.ttkx.deviceinfo.bkchart.popupwindow;import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.PopupWindow;
import android.widget.TextView;import com.blankj.utilcode.util.ConvertUtils;
import com.blankj.utilcode.util.Utils;
import com.ttkx.deviceinfo.R;
import com.ttkx.deviceinfo.bkchart.ArrowsDrawable;
import com.ttkx.deviceinfo.bkchart.GuZhiActivity;import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;import androidx.annotation.IntDef;
import androidx.core.widget.PopupWindowCompat;/*** 估值说明弹窗* Created by liuyu*/
public class SimpleTipsPupopWindow extends PopupWindow {private ArrowsDrawable mBgDrawable;private TextView mTipsTv;private int mShowPosition = TOP;public static final int AUTO_VERTICAL = Gravity.CENTER_VERTICAL;public static final int AUTO_HORIZONTAL = Gravity.CENTER_HORIZONTAL;public static final int LEFT = Gravity.LEFT;public static final int TOP = Gravity.TOP;public static final int RIGHT = Gravity.RIGHT;public static final int BOTTOM = Gravity.BOTTOM;public SimpleTipsPupopWindow(GuZhiActivity context) {this(context, View.inflate(context, R.layout.pupopwindow_view_guzhi_explain, null));}public SimpleTipsPupopWindow(GuZhiActivity context, int layoutId) {this(context, View.inflate(context, layoutId, null));}public SimpleTipsPupopWindow(GuZhiActivity context, View contentView) {super(context);setContentView(contentView);setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));setOutsideTouchable(true);init(contentView);}private void init(View contentView) {mBgDrawable = new ArrowsDrawable(ArrowsDrawable.TOP, ConvertUtils.dp2px(5));mBgDrawable.setCornerRadius(ConvertUtils.dp2px(4));mBgDrawable.setArrowsPadding(ConvertUtils.dp2px(10));mBgDrawable.setArrowsHeight(ConvertUtils.dp2px(5));boolean redMode = true;mBgDrawable.setColor(Color.parseColor(redMode ? "#e6292F3C" : "#f22b3346"));
//        mBgDrawable.setPadding(ConvertUtils.dp2px(10));mTipsTv = contentView.findViewById(R.id.explain_tv);initView(contentView);}/*** 用于自定义布局 初始化* @param contentView*/public void initView(View contentView) {}/*** 设置tips TextView* @param tv*/public void setTipsTv(TextView tv) {mTipsTv = tv;}private int makeDropDownMeasureSpec(int measureSpec) {int mode;if (measureSpec == ViewGroup.LayoutParams.WRAP_CONTENT) {mode = View.MeasureSpec.UNSPECIFIED;} else {mode = View.MeasureSpec.EXACTLY;}return View.MeasureSpec.makeMeasureSpec(View.MeasureSpec.getSize(measureSpec), mode);}public void setTips(String tips) {if (mTipsTv != null) {mTipsTv.setText(tips);}}public void show(View anchor, int os, int oy) {if (mBgDrawable == null) {return;}int showPosition = mShowPosition;int offsetX = 0;int offsetY = 0;int locationX = getLocationOnScreen(anchor)[0];int locationY = getLocationOnScreen(anchor)[1];if (showPosition == LEFT || showPosition == RIGHT || showPosition == AUTO_HORIZONTAL) {mBgDrawable.setArrowsPosition(ArrowsDrawable.LEFT, mTipsTv);getContentView().measure(makeDropDownMeasureSpec(getWidth()), makeDropDownMeasureSpec(getHeight()));int windowWidth = this.getContentView().getMeasuredWidth();os += anchor.getWidth();offsetY = (int) -(anchor.getHeight() / 2 + mBgDrawable.getArrowsCenterDistance());if (showPosition == LEFT) {boolean showLeft = locationX >= windowWidth;offsetX = disHor(showLeft, windowWidth, anchor, os);} else if (showPosition == RIGHT) {boolean showLeft = !(getAppScreenWidth() - (locationX + anchor.getWidth()) > windowWidth);offsetX = disHor(showLeft, windowWidth, anchor, os);} else if (showPosition == AUTO_HORIZONTAL) {int screenWidth = getAppScreenWidth();boolean showLeft = locationX + anchor.getWidth() / 2 >= screenWidth / 2;offsetX = disHor(showLeft, windowWidth, anchor, os);}} else {mBgDrawable.setArrowsPosition(ArrowsDrawable.TOP, mTipsTv);//先设置箭头drawable方向为垂直方向的,因箭头尺寸会影响到计算窗口的高度getContentView().measure(makeDropDownMeasureSpec(getWidth()), makeDropDownMeasureSpec(getHeight()));int windowHeight = this.getContentView().getMeasuredHeight();os += anchor.getWidth() / 2;offsetX = (int) (os - mBgDrawable.getArrowsCenterDistance());if (showPosition == TOP) {int distanceTop = locationY - getStatusBarHeight();//锚点控件距离顶部距离//计算锚点控件在屏幕中的位置offsetY = disVer(distanceTop >= windowHeight, windowHeight, anchor, oy);} else if (showPosition == BOTTOM) {int distanceBottom = getLocationOnScreen(anchor)[1] - anchor.getHeight() - getNavBarHeight();//锚点控件距离底部距离offsetY = disVer(distanceBottom < windowHeight, windowHeight, anchor, oy);} else if (showPosition == AUTO_VERTICAL) {int appScreenHeight = getAppScreenHeight();int anchorCenterY = locationY + anchor.getHeight() / 2;offsetY = disVer(appScreenHeight / 2 < anchorCenterY, windowHeight, anchor, oy);}}//设置textView的padding,防止设置drawable背景不生效Rect padding = mBgDrawable.getPadding();mTipsTv.setPadding(padding.left, padding.top, padding.right, padding.bottom);PopupWindowCompat.showAsDropDown(this, anchor, offsetX, offsetY, Gravity.START);}private int disHor(boolean showLeft, int windowWidth, View anchor, int ox) {int offsetX;if (showLeft) {//锚点控件在屏幕中上方,反之在屏幕中下方mBgDrawable.setArrowsPosition(ArrowsDrawable.RIGHT);offsetX = -windowWidth + ox - anchor.getWidth();} else {mBgDrawable.setArrowsPosition(ArrowsDrawable.LEFT);offsetX = ox;}return offsetX;}private int disVer(boolean showTop, int windowHeight, View anchor, int oy) {int offsetY = 0;if (showTop) {//锚点控件在屏幕中上方,反之在屏幕中下方mBgDrawable.setArrowsPosition(ArrowsDrawable.BOTTOM);offsetY = -(windowHeight + anchor.getHeight() + oy);} else {mBgDrawable.setArrowsPosition(ArrowsDrawable.TOP);offsetY = oy;}return offsetY;}public ArrowsDrawable getArrowsDrawable() {return mBgDrawable;}public void setPadding(int padding) {mBgDrawable.setPadding(padding);}@IntDef({LEFT, RIGHT, TOP, BOTTOM, AUTO_VERTICAL, AUTO_HORIZONTAL})@Retention(RetentionPolicy.SOURCE)public @interface ShowPosition {}/*** 设置显示位置(相对于锚点控件 左边、上方、右边、下面)* 注意:窗口相对控件的方向,与箭头方向是相反的。* LEFT, RIGHT, TOP, BOTTOM** @param showPosition*/public void setShowPosition(@ShowPosition int showPosition) {mShowPosition = showPosition;}private static int[] getLocationOnScreen(View view) {int[] location = new int[2];view.getLocationOnScreen(location);return location;}private static int getStatusBarHeight() {// 获得状态栏高度Resources resources = Resources.getSystem();int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");return resources.getDimensionPixelSize(resourceId);}private static int getNavBarHeight() {Resources res = Resources.getSystem();int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android");if (resourceId != 0) {return res.getDimensionPixelSize(resourceId);} else {return 0;}}private static int getAppScreenHeight() {WindowManager wm = (WindowManager) Utils.getApp().getSystemService(Context.WINDOW_SERVICE);if (wm == null) return -1;Point point = new Point();wm.getDefaultDisplay().getSize(point);return point.y;}private static int getAppScreenWidth() {WindowManager wm = (WindowManager) Utils.getApp().getSystemService(Context.WINDOW_SERVICE);if (wm == null) return -1;Point point = new Point();wm.getDefaultDisplay().getSize(point);return point.x;}
}

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

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

相关文章

C++——STL容器之list链表的讲解

目录 一.list的介绍 二.list类成员函数的讲解 2.2迭代器 三.添加删除数据&#xff1a; 3.1添加&#xff1a; 3.2删除数据 四.排序及去重函数&#xff1a; 错误案例如下&#xff1a; 方法如下&#xff1a; 一.list的介绍 list列表是序列容器&#xff0c;允许在序列内的任何…

页面滚动时隐藏element-ui下拉框/时间弹框

场景 在系统中&#xff0c;当&#xff08;有垂直滚动时&#xff09;点击下拉框后滚动页面&#xff0c;会发现下拉项会遮盖住页面中的元素&#xff0c;不会隐藏 解决&#xff1a;(以vue为例) 在页面滚动或者缩放时隐藏下拉项即可&#xff08;借助点击目标元素&#xff0c;下…

day3 驱动开发 c语言编程

通过ioctl&#xff08;内核应用层&#xff09; 控制led灯三盏&#xff0c;风扇&#xff0c;蜂鸣器&#xff0c;小马达 头文件head.h #ifndef __LED_H__ #define __LED_H__typedef struct {volatile unsigned int TZCR; // 0x000volatile unsigned int res1[2]; // 0x…

vscode远程调试配置

配置目标服务器免密登录 1.本地生成一组公私钥 输入ssh-keygen -t rsa&#xff0c;三次回车 2.公钥拷贝到远程机器&#xff08;注意要用git bash执行&#xff09; ssh-copy-id -i ~/.ssh/id_rsa.pub 用户名目标服务器ip 3.重启目标服务器ssh服务 service sshd restart 4.测…

css实现鼠标滑动左下角弹框带动画效果

代码 <div classNamekuang></div> css代码 .kuang {height: 500px;width: 400px;// background-color: #fff;position: absolute;z-index: 10;bottom: 0;transform: translateX(-390px)}.kuang:hover {animation: myanimation 3s linear 1;animation-fill-mode:f…

Flowable-中间事件-空中间抛出事件

定义 空中间抛出事件是一个 Throwing 事件&#xff0c;在 intermediateThrowEvent 元素下不加入任何的事件定 义元素&#xff0c;就构成一个空中间抛出事件。它通常用于表示流程中的某个状态&#xff0c;在实际使用的过程中可 以通过添加执行监听器&#xff0c;来表示流程状态…

算法通关村第二关——两两交换链表中的节点的问题解析

题目类型 链表反转 题目描述 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点&#xff0c;且必须在不修改节点内部的值的情况下完成本题&#xff0c;即&#xff1a;只能进行节点交换 效果图 题目分析 如果原始顺序是 dummy(虚拟头节点) …

Linux学习之系统函数库

cat /etc/redhat-release看到操作系统的版本是CentOS Linux release 7.6.1810 (Core)&#xff0c;uname -r可以看到内核版本是3.10.0-957.21.3.el7.x86_64&#xff0c;bash --version可以bash的版本是4.2.46。 在/etc/init.d/functions有许多系统定义好的函数&#xff0c;比如…

Swift 对象数组去重

使用 reduce 方法去重 使用 reduce 方法结合 contains 方法可以实现去重。reduce 方法用于将数组的元素进行累积计算&#xff0c;而 contains 方法用于检查元素是否已经存在于结果数组中。 struct SearchRecord: Equatable {let id: Intlet name: String }let records [Sear…

基于ChatGPT聊天的零样本信息提取7.25

基于ChatGPT聊天的零样本信息提取 摘要介绍ChatIE用于零样本IE的多轮 QA 实验总结 摘要 零样本信息提取&#xff08;IE&#xff09;旨在从未注释的文本中构建IE系统。由于很少涉及人类干预&#xff0c;因此具有挑战性。 零样本IE减少了数据标记所需的时间和工作量。最近对大型…

DevOps-Jenkins

Jenkins Jenkins是一个可扩展的持续集成引擎&#xff0c;是一个开源软件项目&#xff0c;旨在提供一个开放易用的软件平台&#xff0c;使软件的持续集成变成可能。 官网 应用场景 场景一 研发人员上传开发好的代码到github代码仓库需要将代码下载nginx服务器部署手动下载再…

递归实现 组合问题+排列问题(DFS)

目录 递归实现排列型枚举 递归实现排列类型枚举 II 递归实现组合型枚举 递归实现组合型枚举 II 递归实现指数型枚举 递归实现指数型枚举 II 递归不是循环&#xff0c;递归利用了系统栈&#xff0c;只要是函数都会被系统管理。当执行到函数地址入口时就会为函数在系统栈上分…

mac 删除自带的ABC输入法保留一个搜狗输入法,搜狗配置一下可以减少很多的敲击键盘和鼠标点击次数

0. 背景 对于开发者来说&#xff0c;经常被中英文切换输入法所困扰&#xff0c;我这边有一个方法&#xff0c;删除mac默认的ABC输入法 仅仅保留搜狗一个输入法&#xff0c;配置一下搜狗输入&#xff1a;哪些指定为英文输入&#xff0c;哪些指定为中文输入&#xff08;符号也可…

wps图表怎么改横纵坐标,MLP 多层感知器和CNN卷积神经网络区别

目录 wps表格横纵坐标轴怎么设置&#xff1f; MLP (Multilayer Perceptron) 多层感知器 CNN (Convolutional Neural Network) 卷积神经网络 多层感知器MLP&#xff0c;全连接网络&#xff0c;DNN三者的关系 wps表格横纵坐标轴怎么设置&#xff1f; 1、打开表格点击图的右侧…

arm 函数栈回溯

大概意思就是arm每个函数开始都会将PC、LR、SP以及FP四个寄存器入栈。 下面我们看一下这四个寄存器里面保存的是什么内存 arm-linux-gnueabi-gcc unwind.c -mapcs -w -g -o unwind&#xff08;需要加上-mapcs才会严格按照上面说的入栈&#xff09; #include <stdio.h> …

雪花算法,在分布式环境下实现高效的ID生成

其实雪花算法比较简单&#xff0c;可能称不上什么算法就是一种构造UID的方法。 点1&#xff1a;UID是一个long类型的41位时间戳&#xff0c;10位存储机器码&#xff0c;12位存储序列号。 点2&#xff1a;时间戳的单位是毫秒&#xff0c;可以同时链接1024台机器&#xff0c;每台…

Android 面试题 线程间通信 六

&#x1f525; 主线程向子线程发送消息 Threadhandler&#x1f525; 子线程中定义Handler&#xff0c;Handler定义在哪个线程中&#xff0c;就跟那个线程绑定&#xff0c;在线程中绑定Handler需要调用Looper.prepare(); 方法&#xff0c;主线程中不调用是因为主线程默认帮你调用…

怎么在线修改图片?分享一个图片修改工具

无论是在个人或商业领域&#xff0c;我们都需要使用高质量的图片来传达信息或提高品牌形象。大尺寸的图片也会占据大量的存储空间和带宽&#xff0c;影响网站的加载速度和用户体验。因此&#xff0c;我们需要一种高效的工具来解决这个问题。今天向大家介绍一款非常实用的图片处…

Javascript -- 数组prototype方法探究

一、数组prototype方法探究 1、不改变原数组 1. concat() 这个是数组拼接方法&#xff0c;可以将两个数组或多个数组拼接并返回一个包含两个数组或多个数组内容的新数组&#xff0c;不会改变原数组 方法里面理论上可以写入n个参数&#xff0c; const arr [1,2]; var str …

Abaqus 导出单元刚度矩阵和全局刚度矩阵

Abaqus 导出单元刚度矩阵和全局刚度矩阵 首次创建&#xff1a;2023.7.29 最后更新&#xff1a;2023.7.29 如有什么改进的地方&#xff0c;欢迎大家讨论&#xff01; 详细情况请查阅&#xff1a;Abaqus Analysis User’s Guide 一、Abaqus 导出单元刚度矩阵 1.生成单元刚度矩阵…