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. 通过.ENV文件来配置ThinkPHP的数据库连接信息

    在ThinkPHP系统根目录创建.env文件,注意WINDOWS无法直接右键创建,使用编辑器保存时设置文件名为.env就可以创建文件.内容如下: .evn文件内容如下: [database] host ...

  2. [JLOI2015]装备购买(线性基)

    [JLOI2015]装备购买 题目描述 脸哥最近在玩一款神奇的游戏,这个游戏里有 nn 件装备,每件装备有 \(m\) 个属性,用向量 \(\mathbf{z_i}\)=\((a_1, \ldots ...

  3. Python学习笔记(5)--数据结构之字典dict

    字典(dict) 定义:键值对集合 初始化:{}, {'1' : 'abc', '2' : 'def'} 1.增加:单个数据直接赋值  update(dict2) ---把dict2的元素加入到dic ...

  4. ArcGIS api for javascript——渲染-计算相等间隔分级

    描述 本例展示了如何配置分级渲染使用一个相等间隔分类.在这个分类类型中,断点被设置为相等的距离. 可以手工添加相等距离的断点:然而,如果数据被修改了,那些断点就会是不合理的.本例自动地计算断点,因此相 ...

  5. ArcGIS api for javascript——用第二个服务的范围设置地图范围

    描述 本例展示了如何设置地图的范围为地图其中一个图层的范围.本例有两个图层:ArcGIS Online上的世界地图图层ArcGISTiledMapServiceLayer和堪萨斯州的要素的图层ArcG ...

  6. Java中Socket上的Read操作堵塞问题

    从Socket上读取对端发过来的数据一般有两种方法: 1)依照字节流读取 BufferedInputStream in = new BufferedInputStream(socket.getInpu ...

  7. bzoj 1010 (单调决策优化)

    能够非常好的证明单调决策性质.用   记sum[i]=sigma(C[1],C[2].....C[k]);f[i]=sum[i]+i;  c=l-1; 有转移dp[i]=min( dp[j]+(f[i ...

  8. Id选择器和Class选择器

    http://www.runoob.com/css/css-id-class.html http://www.w3school.com.cn/css/css_syntax_id_selector.as ...

  9. jquery tmpl插件

    动态请求数据来更新页面是现在非常常用的方法,比如博客评论的分页动态加载,微博的滚动加载和定时请求加载等. 这些情况下,动态请求返回的数据一般不是已拼好的 HTML 就是 JSON 或 XML,总之不在 ...

  10. Restricted Boltzmann Machines

    转自:http://deeplearning.net/tutorial/rbm.html http://blog.csdn.net/mytestmy/article/details/9150213 能 ...