版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xyzdwf/article/details/54289316
原本写在工具类里的滑动菜单连返回按钮都不好处理,就弄成了一个类,增加了状态改变的回调接口。
添加了布局展开监听,在布局展开后获取尺寸,再调用show(),防止定位不准。
create()方法添加了parentView参数,可以指定父容器(为null时为Activity根容器),以便于和其他组件保持层级关系。
public class SldMenu {
public static final int SHOW_TYPE_BOTTOM=0;//底部显示
public static final int SHOW_TYPE_TOP=1;//顶部显示
public static final int MENU_STATE_GONE=0;//关闭
public static final int MENU_STATE_SHOW=1;//显示
public static final int MENU_STATE_SHOW_START=2;//显示开始
public static final int MENU_STATE_GONE_START=3;//关闭开始
private Context context;
private OnStateChangeListener stateCallBack;
//View
private ViewGroup parentView;//父容器
private View contentView;//内容
private View hdVw;//滑动容器
private View sldVw;//滑动体
//Params
private int sldVwHt;//滑动体高度
private int curState=MENU_STATE_GONE;//菜单状态
private int showTp;//显示类型
private int sHeight;//屏幕高度
private int[] hdLyloc = new int[2];//容器位置0:x
private boolean hasParent;//提供了父容器
private boolean aniFlag;//动画进行时标志
private boolean measureFlag;//测量进行时标志
private boolean showFlag;//show()已调用标志
private SldMenu(){}
/**
*打开底部/顶部滑动菜单
* @param context 上下文 Activity
* @param contentView 菜单内容
* @param parentView 父容器,为null时将创建在根View中
* @return 返回值为SldMenu
*/
public static SldMenu create(Context context, View contentView,ViewGroup parentView) {
if (context == null || contentView == null) return null;
final SldMenu thiz=new SldMenu();
thiz.context=context;
thiz.contentView=contentView;
if(parentView!=null)thiz.hasParent=true;
thiz.sHeight= AndUtil.getScreenHeight(context);
VerticalHolderView hdVw = new VerticalHolderView(context);
hdVw.setVerticalScrollBarEnabled(false);
FrameLayout.LayoutParams reLyPrms1 = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
hdVw.setLayoutParams(reLyPrms1);
FrameLayout frmLy = new FrameLayout(context);
FrameLayout.LayoutParams frmLyPrms = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
frmLyPrms.topMargin=thiz.sHeight;
frmLy.setLayoutParams(frmLyPrms);
frmLy.addView(contentView);
hdVw.addView(frmLy);
thiz.hdVw=hdVw;
thiz.sldVw=frmLy;
if(!thiz.hasParent) {
Activity act = (Activity) context;
ViewGroup vg = (ViewGroup) act.getWindow().getDecorView();
thiz.parentView=vg;
}else{
thiz.parentView=parentView;
parentView.setVisibility(View.VISIBLE);
}
thiz.measureFlag=true;//开始测量
ViewTreeObserver vto = thiz.parentView.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {//添加布局展开监听
public void onGlobalLayout() {
thiz.measureFlag=false;
thiz.sldVwHt= thiz.sldVw.getMeasuredHeight();
if(0==thiz.sldVwHt) {//parentView也未展开
thiz.sldVwHt= AndUtil.getViewHeight(thiz.sldVw);
}
thiz.parentView.getLocationOnScreen(thiz.hdLyloc);
thiz.parentView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
if(thiz.showFlag){
thiz.show(thiz.showTp);
}
}
});
thiz.parentView.addView(hdVw);
return thiz;
}
/**
* 展示Menu
* @param showTp 0:底部;其他:顶部
*/
public void show(int showTp) {
showFlag=true;
this.showTp=showTp;
if(measureFlag)return;
hdVw.setOnTouchListener(new MyOnTouchLsn());
int hdoff=hdLyloc[1];
if(showTp==SHOW_TYPE_BOTTOM) {
doBtmMenuAnimation(sHeight, sHeight - hdoff - sldVwHt, 300, true);
}else{
doBtmMenuAnimation(-sldVwHt,0, 300, true);
}
}
/**
*关闭底部/顶部滑动菜单
*/
public void cancle() {
showFlag=false;
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) sldVw.getLayoutParams();
int k=params.topMargin;
if(showTp==SHOW_TYPE_BOTTOM){
doBtmMenuAnimation(k,sHeight, 300, false);
}else{
doBtmMenuAnimation(k,-AndUtil.getViewHeight(sldVw), 300, false);
}
}
/**
* 打开关闭底部/顶部滑动菜单动画
* @param begin 位置开始
* @param end 位置结束
* @param duration 持续时间
* @param b false:动画结束移除View
*/
private void doBtmMenuAnimation(final int begin, final int end, int duration, final boolean b) {
final FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) sldVw.getLayoutParams();
ValueAnimator mAnimator = ValueAnimator.ofInt(begin, end);
mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int aniVal = (int) animation.getAnimatedValue();
params.topMargin = aniVal;
sldVw.setLayoutParams(params);
}
});
mAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
aniFlag=true;
if(!b&&curState==MENU_STATE_SHOW){
curState=MENU_STATE_GONE_START;
if(stateCallBack!=null){
stateCallBack.onStateChange(curState);
}
}else if(b&&curState==MENU_STATE_GONE){
curState=MENU_STATE_SHOW_START;
if(stateCallBack!=null){
stateCallBack.onStateChange(curState);
}
}
}
@Override
public void onAnimationEnd(Animator animation) {
params.topMargin = end;
sldVw.setLayoutParams(params);
if(!b&&curState==MENU_STATE_GONE_START){
removeBtmMenuVw();
curState=MENU_STATE_GONE;
if(stateCallBack!=null){
stateCallBack.onStateChange(curState);
}
}else if(b&&curState==MENU_STATE_SHOW_START){
curState=MENU_STATE_SHOW;
if(stateCallBack!=null){
stateCallBack.onStateChange(curState);
}
}
aniFlag=false;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mAnimator.setInterpolator(new DecelerateInterpolator());
mAnimator.setDuration(duration);
mAnimator.start();
}
/**
*移除底部/顶部滑动菜单View
*/
private void removeBtmMenuVw(){
if(hasParent){
if(1==parentView.getChildCount()) {
parentView.setVisibility(View.GONE);
}
}
parentView.removeView(hdVw);
}
/**
* 打开或关闭状态改变回调借口
*/
public interface OnStateChangeListener
{
void onStateChange(int state);
}
private class MyOnTouchLsn implements View.OnTouchListener{
private Context contexta=context;
private float ny, ny1, ry; //y坐标历史和最新y坐标
private int magtop; //margin top
private boolean mvf = false;//move flag 移动标志
private FrameLayout.LayoutParams params;
private int reLHt;//滑动部分高度
private int hdoff;//容器偏移
private boolean myFlg = false;
public MyOnTouchLsn() {
this.reLHt=AndUtil.getViewHeight(sldVw);
this.hdoff=hdLyloc[1];
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (aniFlag){
myFlg = true;
return myFlg;
}
if(myFlg){//拦截重复触发
if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL){
myFlg = false;
//Log.w("SldMenu¥MyOnTouchLsn", "nomeaning touch stoped!");
}
return true;
}
ry = (int) event.getRawY();
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mvf = false;
if(showTp==0){
magtop = sHeight-hdoff-reLHt;
}else{
magtop = 0;
}
params = (FrameLayout.LayoutParams) sldVw.getLayoutParams();
} else if (event.getAction() == MotionEvent.ACTION_UP||event.getAction() == MotionEvent.ACTION_CANCEL) {
if (mvf) {
boolean b = false;
if (ny > ny1) {
b = true;
}
int endp;
if(showTp==0) {
endp=b?sHeight:sHeight - hdoff - reLHt;
b=!b;
}else{
endp=b?0:-reLHt;
}
doBtmMenuAnimation(magtop,endp, 300, b);
} else {//这里处理类似单击事件
int lnup=magtop+hdoff;
int lndn=lnup+reLHt;
if(ry>lndn||ry<lnup){
cancle();
}
}
} else if (event.getAction() == MotionEvent.ACTION_MOVE && Math.abs(ry - ny) >= 5) {
mvf = true;
magtop += (int) (ry - ny);
if(showTp==0){
int mxmg=sHeight-hdoff-reLHt;
if(magtop<=mxmg){
magtop=mxmg;
}
}else{
if(magtop>=0){
magtop=0;
}
}
if (params != null) {
params.topMargin = magtop;
sldVw.setLayoutParams(params);
}
}
ny1 = ny;
ny = ry;
return true;
}
}
public SldMenu setOnStateChangeListener(OnStateChangeListener stateCallBack) {
this.stateCallBack = stateCallBack;
return this;
}
public View getContentView() {
return contentView;
}
}
相关的类,滑动容器,其实就是ScrollView取消了Touch事件:
public class VerticalHolderView extends ScrollView {
public VerticalHolderView(Context context) {
super(context);
}
public VerticalHolderView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VerticalHolderView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return false;
}
}
工具类中的方法:
public class AndUtil {
public static int dp2Px(Context context, float dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dp, context.getResources().getDisplayMetrics());
}
public static float px2Dp(Context context, float px) {
final float scale = context.getResources().getDisplayMetrics().density;
return (px / scale);
}
public static int sp2px(Context context, float spVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
spVal, context.getResources().getDisplayMetrics());
}
public static float px2sp(Context context, float pxVal) {
return (pxVal / context.getResources().getDisplayMetrics().scaledDensity);
}
/**
* 获得屏幕宽度
*
* @param context
* @return
*/
public static int getScreenWidth(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.widthPixels;
}
/**
* 获得高度
*
* @param context
* @return
*/
public static int getScreenHeight(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.heightPixels;
}
public static int getViewWidth(View view) {
int width = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int height = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(width, height);
int w = view.getMeasuredWidth();
return w;
}
public static int getViewHeight(View view) {
int width = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int height = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(width, height);
int h = view.getMeasuredHeight();
return h;
}
最后测试下,show之前添加监听:
tmpSldMenu = SldMenu.create(this, hdvw,secondHolderLayer);
tmpSldMenu.setOnStateChangeListener(new SldMenu.OnStateChangeListener() {
@Override
public void onStateChange(int state) {
Log.i(TAG,"--->"+state);
}
});
tmpSldMenu.show(0);