我是靠谱客的博主 顺利蜻蜓,最近开发中收集的这篇文章主要介绍简单定制Android控件(3) - 打造通用的PopupWindow(一),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

国际惯例,先上地址

https://github.com/razerdp/BasePopup

PS:效果图都放在了github,github有着我继承该类做出来的popupWindow

//2016-01-15 目前只写了两个PopupWindow

效果图:

普通的放大缩小:


从下方弹出:




通常情况下,面对各种浮动窗口,选择窗口什么的,我们通常都是使用popupWindow,但是很多时候我们都希望popupWindow可以在弹出的时候带有动画,但是就popup本身而言,使用的动画是在是太不舒服不自由了。


通常情况下,我们弄个popupWindow的动画都是这么玩的

 popupWindow.setAnimationStyle(R.style.PopMenuAnimation);
我们还得去styles.xml弄弄我们的进入/退出动画,这多不自然啊,而且说好的控制呢对吧


于是这次我们就来打造一个通用的popupWindow,让我们可以随心自由的设置我们的popupWindow


这次我们要实现的popupWindow起码要实现以下几个要求{

  1.   自由的定义样式
  2.   便利的动画实现
  3.   可扩展
  4.   代码简洁易懂
}

好的,说了那么多,接下来我们就开工。

开工之前,我们先谈谈要求和实现方法吧:

  第一点,自由的定义样式,popupWindow在new出来的时候参数里面有一个参数是View,这意味着popupWindow本身就支持添加view(其实楼主我一直都把popupWindow看作一个浮动的viewGroup)

  第二点,便利的动画实现,开头说过,自带的popupWindow动画实现是在不舒服,于是我们打算这么做,动画由我们自己来指定,popupWindow只需要播放就好了。在第一点我说过,我把popupWindow看作一个浮动的viewGroup,既然有了viewGroup,那就意味着必定有view对吧,有了view,那就意味着必定有view的animation对吧,于是第二点的初步构造就出来了,popupWindow包裹着viewGroup,viewGroup里面的view(或者viewGroup)播放动画,实现我们的第二点需求。

  第三点,可扩展,可扩展意味着我们可以轻易的继承父类从而实现我们各种各样的popup,比如listPopup,inputPopup甚至是含有viewpager的popup。那么显然,我们需要一个抽象类,作为顶级父类,并限定子类规则,防止不可预料的问题。
  
  第四点,嗯。。。。。看个人代码风格吧
   ps:楼主是个注释/分块 狂魔


正文:

我们首先创建一个abstract class,作为顶级父类,取名叫BasePopup就好了。
首先我们需要一个popupWindow,作为一个popup用来浮动在当前的activity上面,然后需要一个view,作为popup的整体,然后就是一些参数设置什么的,比如是否需要输入之类的,这是后话。

于是我们就有了下面的一段代码:
public abstract class BasePopupWindow implements ViewCreate {
private static final String TAG = "BasePopupWindow";
//元素定义
protected PopupWindow mPopupWindow;
//popup视图
protected View mPopupView;
protected Activity mContext;
//是否自动弹出输入框(default:false)
private boolean autoShowInputMethod = false;
private OnDismissListener mOnDismissListener;
public BasePopupWindow(Activity context) {
mContext = context;
mPopupView = getPopupView();
mPopupView.setFocusable(true);
mPopupView.setFocusableInTouchMode(true);
//默认占满全屏
mPopupWindow =
new PopupWindow(mPopupView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
//指定透明背景,点击外面相关
mPopupWindow.setBackgroundDrawable(new ColorDrawable());
mPopupWindow.setFocusable(true);
mPopupWindow.setOutsideTouchable(true);
//无需动画
mPopupWindow.setAnimationStyle(0);
}
public BasePopupWindow(Activity context, int w, int h) {
mContext = context;
mPopupView = getPopupView();
mPopupView.setFocusable(true);
mPopupView.setFocusableInTouchMode(true);
//默认占满全屏
mPopupWindow = new PopupWindow(mPopupView, w, h);
//指定透明背景,点击外面相关
mPopupWindow.setBackgroundDrawable(new ColorDrawable());
mPopupWindow.setFocusable(true);
mPopupWindow.setOutsideTouchable(true);
//无需动画
mPopupWindow.setAnimationStyle(0);
}

设置两个构造器是为了扩展,因为默认状态下我们的popup是全屏显示,但是特殊的popup呢,最经典的例子,微信朋友圈的点赞/评论弹出来的那个东东,我们可以用popup来做,但很明显我们不可以用全屏的popup对吧,于是就有了第二个构造器

从代码我们看到我们实现了一个接口,这个接口只提供两个方法,具体如下
/**
* Created by 大灯泡 on 2016/1/14.
*/
public interface ViewCreate {
View getPopupView();
View getAnimaView();
}

getPopupView,在构造器我们可以看到,popupWindow的contentView就是通过这个得到
getAnimaView,明显用来播放动画用的


 基本构造有了,接下来就是对子类的限定

//------------------------------------------抽象-----------------------------------------------
public abstract Animation getAnimation();
public abstract AnimationSet getAnimationSet();
public abstract View getInputView();

期中getAnimation提供给子类用来设置播放动画,AnimationSet也是,但是AnimationSet是使用ObjectAnima的,也就是物理上改变的view参数,Animation只是改变视觉,对于物理事件(比如点击事件)的位置是不涉及改变的。


getInputView用于获取需要输入内容的popup里面的输入框,用于自动弹出输入法。

对子类规则定好后,接下来就是实现show方法。

对于popup我们都知道有一个showAtLocation方法来展示popup,我们这里也使用这个。

//------------------------------------------showPopup-----------------------------------------------
public void showPopupWindow() {
try {
tryToShowPopup(0, null);
} catch (Exception e) {
Log.e(TAG, "show error");
e.printStackTrace();
}
}
public void showPopupWindow(int res) {
try {
tryToShowPopup(res, null);
} catch (Exception e) {
Log.e(TAG, "show error");
e.printStackTrace();
}
}
public void showPopupWindow(View v) {
try {
tryToShowPopup(0, v);
} catch (Exception e) {
Log.e(TAG, "show error");
e.printStackTrace();
}
}
//------------------------------------------Methods-----------------------------------------------
private void tryToShowPopup(int res, View v) throws Exception {
//传递了view
if (res == 0 && v != null) {
mPopupWindow.showAtLocation(v, Gravity.RIGHT | Gravity.CENTER_HORIZONTAL, 0, 0);
}
//传递了res
if (res != 0 && v == null) {
mPopupWindow.showAtLocation(mContext.findViewById(res), Gravity.RIGHT | Gravity.CENTER_HORIZONTAL, 0, 0);
}
//什么都没传递,取顶级view的id
if (res == 0 && v == null) {
mPopupWindow.showAtLocation(mContext.findViewById(android.R.id.content),
Gravity.RIGHT | Gravity.CENTER_HORIZONTAL,
0,
0
);
}
if (getAnimation() != null && getAnimaView() != null) {
getAnimaView().startAnimation(getAnimation());
}
//ViewHelper.setPivotX是包nineoldAndroid的方法,用于兼容低版本的anima以及方便的view工具
if (getAnimation() == null && getAnimationSet() != null && getAnimaView() != null &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ViewHelper.setPivotX(getAnimaView(), getAnimaView().getMeasuredWidth() / 2.0f);
ViewHelper.setPivotY(getAnimaView(), getAnimaView().getMeasuredHeight() / 2.0f);
getAnimationSet().start();
}
//自动弹出键盘
if (autoShowInputMethod && getInputView() != null) {
InputMethodUtils.showInputMethod(getInputView(), 150);
}
}




相关注释都写上了,这里就不解释
附上InputMethodUtils的代码:
150ms后弹出软键盘是为了给窗体绘制时间。
/**
* Created by 大灯泡 on 2016/1/14.
* 显示键盘d工具类
*/
public class InputMethodUtils {
/** 显示软键盘 */
public static void showInputMethod(View view) {
InputMethodManager imm = (InputMethodManager) view.getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
}
}
/** 显示软键盘 */
public static void showInputMethod(Context context) {
InputMethodManager imm = (InputMethodManager) context
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
}
/** 多少时间后显示软键盘 */
public static void showInputMethod(final View view, long delayMillis) {
// 显示输入法
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
InputMethodUtils.showInputMethod(view);
}
}, delayMillis);
}
}

最后就是一些Setter/Getter和接口方法了
总体代码:


BasePopup.java:
package razerdp.basepopup.basepopup;
import android.app.Activity;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.PopupWindow;
import com.nineoldandroids.view.ViewHelper;
import razerdp.basepopup.utils.InputMethodUtils;
/**
* Created by 大灯泡 on 2016/1/14.
* 通用的popupWindow
*/
public abstract class BasePopupWindow implements ViewCreate {
private static final String TAG = "BasePopupWindow";
//元素定义
protected PopupWindow mPopupWindow;
//popup视图
protected View mPopupView;
protected Activity mContext;
//是否自动弹出输入框(default:false)
private boolean autoShowInputMethod = false;
private OnDismissListener mOnDismissListener;
public BasePopupWindow(Activity context) {
mContext = context;
mPopupView = getPopupView();
mPopupView.setFocusable(true);
mPopupView.setFocusableInTouchMode(true);
//默认占满全屏
mPopupWindow =
new PopupWindow(mPopupView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
//指定透明背景,back键相关
mPopupWindow.setBackgroundDrawable(new ColorDrawable());
mPopupWindow.setFocusable(true);
mPopupWindow.setOutsideTouchable(true);
//无需动画
mPopupWindow.setAnimationStyle(0);
}
public BasePopupWindow(Activity context, int w, int h) {
mContext = context;
mPopupView = getPopupView();
mPopupView.setFocusable(true);
mPopupView.setFocusableInTouchMode(true);
//默认占满全屏
mPopupWindow = new PopupWindow(mPopupView, w, h);
//指定透明背景,back键相关
mPopupWindow.setBackgroundDrawable(new ColorDrawable());
mPopupWindow.setFocusable(true);
mPopupWindow.setOutsideTouchable(true);
//无需动画
mPopupWindow.setAnimationStyle(0);
}
//------------------------------------------抽象-----------------------------------------------
public abstract Animation getAnimation();
public abstract AnimationSet getAnimationSet();
public abstract View getInputView();
//------------------------------------------showPopup-----------------------------------------------
public void showPopupWindow() {
try {
tryToShowPopup(0, null);
} catch (Exception e) {
Log.e(TAG, "show error");
e.printStackTrace();
}
}
public void showPopupWindow(int res) {
try {
tryToShowPopup(res, null);
} catch (Exception e) {
Log.e(TAG, "show error");
e.printStackTrace();
}
}
public void showPopupWindow(View v) {
try {
tryToShowPopup(0, v);
} catch (Exception e) {
Log.e(TAG, "show error");
e.printStackTrace();
}
}
//------------------------------------------Methods-----------------------------------------------
private void tryToShowPopup(int res, View v) throws Exception {
//传递了view
if (res == 0 && v != null) {
mPopupWindow.showAtLocation(v, Gravity.RIGHT | Gravity.CENTER_HORIZONTAL, 0, 0);
}
//传递了res
if (res != 0 && v == null) {
mPopupWindow.showAtLocation(mContext.findViewById(res), Gravity.RIGHT | Gravity.CENTER_HORIZONTAL, 0, 0);
}
//什么都没传递,取顶级view的id
if (res == 0 && v == null) {
mPopupWindow.showAtLocation(mContext.findViewById(android.R.id.content),
Gravity.RIGHT | Gravity.CENTER_HORIZONTAL,
0,
0
);
}
if (getAnimation() != null && getAnimaView() != null) {
getAnimaView().startAnimation(getAnimation());
}
//ViewHelper.setPivotX是包nineoldAndroid的方法,用于兼容低版本的anima以及方便的view工具
if (getAnimation() == null && getAnimationSet() != null && getAnimaView() != null &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ViewHelper.setPivotX(getAnimaView(), getAnimaView().getMeasuredWidth() / 2.0f);
ViewHelper.setPivotY(getAnimaView(), getAnimaView().getMeasuredHeight() / 2.0f);
getAnimationSet().start();
}
//自动弹出键盘
if (autoShowInputMethod && getInputView() != null) {
InputMethodUtils.showInputMethod(getInputView(), 150);
}
}
public void setAdjustInputMethod(boolean needAdjust) {
if (needAdjust) {
mPopupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
} else {
mPopupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
}
}
public void setAutoShowInputMethod(boolean autoShow) {
this.autoShowInputMethod = autoShow;
if (autoShow) {
setAdjustInputMethod(true);
} else {
setAdjustInputMethod(false);
}
}
public void setBackPressEnable(boolean backPressEnable){
if (backPressEnable){
mPopupWindow.setBackgroundDrawable(new ColorDrawable());
}else {
mPopupWindow.setBackgroundDrawable(null);
}
}
//------------------------------------------Getter/Setter-----------------------------------------------
public boolean isShowing() {
return mPopupWindow.isShowing();
}
public OnDismissListener getOnDismissListener() {
return mOnDismissListener;
}
public void setOnDismissListener(OnDismissListener onDismissListener) {
mOnDismissListener = onDismissListener;
if (mOnDismissListener!=null){
mPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
mOnDismissListener.onDismiss();
}
});
}
}
//------------------------------------------状态控制-----------------------------------------------
public void dismiss() {
try {
mPopupWindow.dismiss();
} catch (Exception e) {
Log.d(TAG, "dismiss error");
}
}
//------------------------------------------Anima-----------------------------------------------
/**
* 生成TranslateAnimation
* @param durationMillis 动画显示时间
* @param start 初始位置
*/
protected Animation getTranslateAnimation(int start, int end, int durationMillis) {
Animation translateAnimation = new TranslateAnimation(0, 0, start, end);
translateAnimation.setDuration(durationMillis);
translateAnimation.setFillEnabled(true);
translateAnimation.setFillAfter(true);
return translateAnimation;
}
/**
* 生成ScaleAnimation
*/
protected Animation getScaleAnimation(float fromX, float toX, float fromY, float toY,
int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {
Animation scaleAnimation =
new ScaleAnimation(fromX, toX, fromY, toY, pivotXType, pivotXValue, pivotYType,
pivotYValue);
scaleAnimation.setDuration(300);
scaleAnimation.setFillEnabled(true);
scaleAnimation.setFillAfter(true);
return scaleAnimation;
}
/**
* 生成自定义ScaleAnimation
*/
protected Animation getDefaultScaleAnimation() {
Animation scaleAnimation =
new ScaleAnimation(0f, 1f, 0f, 1f, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(300);
scaleAnimation.setInterpolator(new AccelerateInterpolator());
scaleAnimation.setFillEnabled(true);
scaleAnimation.setFillAfter(true);
return scaleAnimation;
}
/**
* 生成默认的AlphaAnimation
* */
protected Animation getDefaultAlphaAnimation() {
Animation alphaAnimation =
new AlphaAnimation(0.0f, 1.0f);
alphaAnimation.setDuration(300);
alphaAnimation.setInterpolator(new AccelerateInterpolator());
alphaAnimation.setFillEnabled(true);
alphaAnimation.setFillAfter(true);
return alphaAnimation;
}
//------------------------------------------Interface-----------------------------------------------
public interface OnDismissListener {
void onDismiss();
}
}



ViewCreate.java:
import android.view.View;
/**
* Created by 大灯泡 on 2016/1/14.
*/
public interface ViewCreate {
View getPopupView();
View getAnimaView();
}

InputMethodUtils.java:
import android.content.Context;
import android.os.Handler;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
/**
* Created by 大灯泡 on 2016/1/14.
* 显示键盘d工具类
*/
public class InputMethodUtils {
/** 显示软键盘 */
public static void showInputMethod(View view) {
InputMethodManager imm = (InputMethodManager) view.getContext()
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
}
}
/** 显示软键盘 */
public static void showInputMethod(Context context) {
InputMethodManager imm = (InputMethodManager) context
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
}
/** 多少时间后显示软键盘 */
public static void showInputMethod(final View view, long delayMillis) {
// 显示输入法
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
InputMethodUtils.showInputMethod(view);
}
}, delayMillis);
}
}


下一章继续,通过继承我们的BasePopup来打造我们的popup

最后

以上就是顺利蜻蜓为你收集整理的简单定制Android控件(3) - 打造通用的PopupWindow(一)的全部内容,希望文章能够帮你解决简单定制Android控件(3) - 打造通用的PopupWindow(一)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(60)

评论列表共有 0 条评论

立即
投稿
返回
顶部