47.Android 自己定义PopupWindow技巧


前言

事实上PopupWindow自己定义过程是非常easy的,唯一头疼的是:PopupWindow显示的定位问题。

定位问题尤为恶心一点:有时候要涉及到PopupWindow的宽高问题。我们都知道,在没show之前是拿不到宽高的,show的时候定位须要宽高。如此矛盾。

下面,都给予回答

其次的问题也有:PopupWindow的显示、消失动画设计问题。

下面也在我自己定义的PopupWindow中提供了三个简单的定位方法:

  • 显示在控件的下左位置

  • 显示在控件的下中位置

  • 显示在控件的下右位置


PopupWindow的宽高

我们能够在PopupWindow初始化的时候。强制绘制Layout,而拿到PopupWindow的宽高。

// 用于保存PopupWindow的宽度
private int width;
// 用于保存PopupWindow的高度
private int height; public CustomPopupWindow(Activity activity) {
super(activity);
this.activity = activity;
this.initPopupWindow();
} private void initPopupWindow() {
LayoutInflater inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.contentView = inflater.inflate(R.layout.popupwindow_custom, null);
this.setContentView(contentView);
// 设置弹出窗口的宽
this.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
// 设置弹出窗口的高
this.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
// 设置弹出窗口可点击
this.setTouchable(true);
this.setFocusable(true);
// 设置点击是否消失
this.setOutsideTouchable(true);
//设置弹出窗口动画效果
this.setAnimationStyle(R.style.PopupAnimation);
//实例化一个ColorDrawable颜色为半透明
ColorDrawable background = new ColorDrawable(0x4f000000);
//设置弹出窗口的背景
this.setBackgroundDrawable(background);
// 绘制
this.mandatoryDraw();
} /**
* 强制绘制popupWindowView,而且初始化popupWindowView的尺寸
*/
private void mandatoryDraw() {
this.contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
/**
* 强制刷新后拿到PopupWindow的宽高
*/
this.width = this.contentView.getMeasuredWidth();
this.height = this.contentView.getMeasuredHeight();
}

PopupWindow定位在下左位置

/**
* 显示在控件的下左方
*
* @param parent parent
*/
public void showAtDropDownLeft(View parent) {
if (parent.getVisibility() == View.GONE) {
this.showAtLocation(parent, 0, 0, 0);
} else {
// x y
int[] location = new int[2];
//获取在整个屏幕内的绝对坐标
parent.getLocationOnScreen(location);
this.showAtLocation(parent, 0, location[0], location[1] + parent.getHeight());
}
}

PopupWindow定位在下中位置

/**
* 显示在控件的下中方
*
* @param parent parent
*/
public void showAtDropDownCenter(View parent) {
if (parent.getVisibility() == View.GONE) {
this.showAtLocation(parent, 0, 0, 0);
} else {
// x y
int[] location = new int[2];
//获取在整个屏幕内的绝对坐标
parent.getLocationOnScreen(location);
this.showAtLocation(parent, 0, location[0] / 2 + parent.getWidth() / 2 - this.width / 6, location[1] + parent.getHeight());
}
}

PopupWindow定位在下右位置

/**
* 显示在控件的下右方
*
* @param parent parent
*/
public void showAtDropDownRight(View parent) {
if (parent.getVisibility() == View.GONE) {
this.showAtLocation(parent, 0, 0, 0);
} else {
// x y
int[] location = new int[2];
//获取在整个屏幕内的绝对坐标
parent.getLocationOnScreen(location);
this.showAtLocation(parent, 0, location[0] + parent.getWidth() - this.width, location[1] + parent.getHeight());
}
}

PopupWindow动画

设计一个从PopWindow開始的时候右上角逐步展示,然后结束的时候往右上角逐步收起的动画:

styles.xml

<style name="PopupAnimation" parent="android:Animation" mce_bogus="1">
<item name="android:windowEnterAnimation">@anim/popwindow_in</item>
<item name="android:windowExitAnimation">@anim/popwindow_out</item>
</style>

popwindow_in.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator"> <!--
时间 0.2秒
開始的时候 x y 全是0 没有大小
结束的时候 x y 全是1 实际大小
pivotX 100% 表示最右边
pivotY 0% 表示最顶边
以上定位右上角 缩放时不变位置
-->
<scale
android:duration="200"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:pivotX="100%"
android:pivotY="0%"
android:toXScale="1.0"
android:toYScale="1.0" />
<!--
时间 0.2秒
開始全透明
结束一点都不透明
-->
<alpha
android:duration="200"
android:fromAlpha="0.0"
android:toAlpha="1.0" />
</set>

popwindow_out.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/decelerate_interpolator">
<!--
时间 0.2秒
開始的时候 x y 全是1 实际大小
结束的时候 x y 全是0 没有大小
pivotX 100% 表示最右边
pivotY 0% 表示最顶边
以上定位右上角 缩放时不变位置
-->
<scale
android:duration="200"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="100%"
android:pivotY="0%"
android:toXScale="0.0"
android:toYScale="0.0" /> <!--
时间 0.2秒
開始一点都不透明
结束全透明
-->
<alpha
android:duration="200"
android:fromAlpha="1.0"
android:toAlpha="0.0" />
</set>

自己定义PopupWindow

public class CustomPopupWindow extends android.widget.PopupWindow {

    private Activity activity;
private View contentView; // 用于保存PopupWindow的宽度
private int width;
// 用于保存PopupWindow的高度
private int height; public CustomPopupWindow(Activity activity) {
super(activity);
this.activity = activity;
this.initPopupWindow();
} private void initPopupWindow() {
LayoutInflater inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.contentView = inflater.inflate(R.layout.popupwindow_custom, null);
this.setContentView(contentView);
// 设置弹出窗口的宽
this.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
// 设置弹出窗口的高
this.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
// 设置弹出窗口可点击
this.setTouchable(true);
this.setFocusable(true);
// 设置点击是否消失
this.setOutsideTouchable(true);
//设置弹出窗口动画效果
this.setAnimationStyle(R.style.PopupAnimation);
//实例化一个ColorDrawable颜色为半透明
ColorDrawable background = new ColorDrawable(0x4f000000);
//设置弹出窗口的背景
this.setBackgroundDrawable(background);
// 绘制
this.mandatoryDraw();
} /**
* 强制绘制popupWindowView。而且初始化popupWindowView的尺寸
*/
private void mandatoryDraw() {
this.contentView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
/**
* 强制刷新后拿到PopupWindow的宽高
*/
this.width = this.contentView.getMeasuredWidth();
this.height = this.contentView.getMeasuredHeight();
} /**
* 显示在控件的下右方
*
* @param parent parent
*/
public void showAtDropDownRight(View parent) {
if (parent.getVisibility() == View.GONE) {
this.showAtLocation(parent, 0, 0, 0);
} else {
// x y
int[] location = new int[2];
//获取在整个屏幕内的绝对坐标
parent.getLocationOnScreen(location);
this.showAtLocation(parent, 0, location[0] + parent.getWidth() - this.width, location[1] + parent.getHeight());
}
} /**
* 显示在控件的下左方
*
* @param parent parent
*/
public void showAtDropDownLeft(View parent) {
if (parent.getVisibility() == View.GONE) {
this.showAtLocation(parent, 0, 0, 0);
} else {
// x y
int[] location = new int[2];
//获取在整个屏幕内的绝对坐标
parent.getLocationOnScreen(location);
this.showAtLocation(parent, 0, location[0], location[1] + parent.getHeight());
}
} /**
* 显示在控件的下中方
*
* @param parent parent
*/
public void showAtDropDownCenter(View parent) {
if (parent.getVisibility() == View.GONE) {
this.showAtLocation(parent, 0, 0, 0);
} else {
// x y
int[] location = new int[2];
//获取在整个屏幕内的绝对坐标
parent.getLocationOnScreen(location);
this.showAtLocation(parent, 0, location[0] / 2 + parent.getWidth() / 2 - this.width / 6, location[1] + parent.getHeight());
}
} public static class PopupWindowBuilder {
private static String activityHashCode;
private static CustomPopupWindow popupWindow;
public static PopupWindowBuilder ourInstance; public static PopupWindowBuilder getInstance(Activity activity) {
if (ourInstance == null) ourInstance = new PopupWindowBuilder();
String hashCode = String.valueOf(activity.hashCode());
/**
* 不同一个Activity
*/
if (!hashCode.equals(String.valueOf(activityHashCode))) {
activityHashCode = hashCode;
popupWindow = new CustomPopupWindow(activity);
}
return ourInstance;
} public PopupWindowBuilder setTouchable(boolean touchable) {
popupWindow.setTouchable(touchable);
return this;
} public PopupWindowBuilder setAnimationStyle(int animationStyle) {
popupWindow.setAnimationStyle(animationStyle);
return this;
} public PopupWindowBuilder setBackgroundDrawable(Drawable background) {
popupWindow.setBackgroundDrawable(background);
return this;
} public CustomPopupWindow getPopupWindow() {
popupWindow.update();
return popupWindow;
} } }

效果图

47.Android 自己定义PopupWindow技巧的更多相关文章

  1. 最强 Android Studio 使用小技巧和快捷键

    写在前面 本文翻译自 Android Studio Tips by Philippe Breault,一共收集了62个 Android Studio 使用小技巧和快捷键. 根据这些小技巧的使用场景,本 ...

  2. 最强 Android Studio 使用小技巧和快捷键总结

    最强 Android Studio 使用小技巧和快捷键总结   写在前面 本文翻译自 Android Studio Tips by Philippe Breault,一共收集了62个 Android ...

  3. Android Studio 使用小技巧和快捷键

    Android Studio 使用小技巧和快捷键 Alt+回车 导入包,自己主动修正 Ctrl+N   查找类 Ctrl+Shift+N 查找文件 Ctrl+Alt+L  格式化代码 Ctrl+Alt ...

  4. Android开发之PopupWindow

      /* *  Android开发之PopupWindow * *  Created on: 2011-8-8 *  Author: blueeagle *  Email: liujiaxiang@g ...

  5. Android-自己定义PopupWindow

    Android-自己定义PopupWindow 2014年5月12日 PopupWindow在应用中应该是随处可见的,非经常常使用到,比方在旧版本号的微信其中就用到下拉的PopupWindow.那是自 ...

  6. Android课程---Android Studio使用小技巧:提取方法代码片段

    这篇文章主要介绍了Android Studio使用小技巧:提取方法代码片段,本文分享了一个快速复制粘贴方法代码片段的小技巧,并用GIF图演示,需要的朋友可以参考下 今天来给大家介绍一个非常有用的Stu ...

  7. Android自己定义DataTimePicker(日期选择器)

    Android自己定义DataTimePicker(日期选择器)  笔者有一段时间没有发表关于Android的文章了,关于Android自己定义组件笔者有好几篇想跟大家分享的,后期会记录在博客中.本篇 ...

  8. Android UI--自定义ListView(实现下拉刷新+加载更多)

    Android UI--自定义ListView(实现下拉刷新+加载更多) 关于实现ListView下拉刷新和加载更多的实现,我想网上一搜就一堆.不过我就没发现比较实用的,要不就是实现起来太复杂,要不就 ...

  9. Android自己定义组件系列【7】——进阶实践(4)

    上一篇<Android自己定义组件系列[6]--进阶实践(3)>中补充了关于Android中事件分发的过程知识.这一篇我们接着来分析任老师的<可下拉的PinnedHeaderExpa ...

随机推荐

  1. 使用let's encrypt为你的Ubuntu14+nginx网站保驾护航!

    finch最近正在研究一个新的网站系统,闲的没事想搞搞ssl,结果搞了两天,遇到很多问题,现在记录并分享一下经验. 环境之前搭建好了是Ubuntu14+nginx+php5+mysql 现在开始使用l ...

  2. mod_php模式原理探析

    1.PHP与Apache工作模式 在传统的LAMP架构中,PHP与Apache交互时,至少有两种方式『运行PHP』: 使用CGI:Apache发送请求至php-cgi进程,php-cgi进程调用PHP ...

  3. P3168 [CQOI2015]任务查询系统(主席树)

    题目描述 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei ...

  4. 【Uva 11584】Partitioning by Palindromes

    [Link]:https://cn.vjudge.net/contest/170078#problem/G [Description] 给你若干个只由小写字母组成的字符串; 问你,这个字符串,最少能由 ...

  5. js获取css

    原帖地址:http://kingphp.blog.163.com/blog/static/20042324420120109438458/ 我们通过dom.style获得的属性是有限制的,只能获取ht ...

  6. OpenStack依然大行其道,可是否能等来属于自己的时代

    版权声明:不论什么转载需全文转载并保留来源(微信公众号techculture)和该声明,并同一时候转载文后的二维码.否则视作侵权. OpenStack在云计算领域依然火热,甚至能够说势不可挡.这可能是 ...

  7. CCNP路由实验之六 动态路由协议之IS-IS

     CCNP路由实验之六动态路由协议之IS-IS 动态路由协议能够自己主动的发现远程网络.仅仅要网络拓扑结构发生了变化.路由器就会相互交换路由信息,不仅能够自己主动获知新添加的网络.还能够在当前网络 ...

  8. iOS 一个ViewController上显示2个tableView的方法

    1.在StoryBoard上创建2个tableView,并用autolayout约束. 2.在ViewController上拖进来. @property (weak, nonatomic) IBOut ...

  9. vijos - P1176奇怪的数列 (递归 + 找规律)

    P1176奇怪的数列 Accepted 标签:[显示标签] 背景 一天.学军数学小组的成员遇到了一个奇怪的数列,正巧信息小组的你碰到了他们. 于是他们把这个数列展示给你-- 描写叙述 这个数列是这种: ...

  10. docker 笔记1

    如果想要删除所有container的话再加一个指令: docker stop $(docker ps -a -q) 如果想要删除所有container的话再加一个指令: docker rm $(doc ...