UI--仿IOS控件之ActionSheet样式 and more..

本文详述了在Android中实现仿iOS ActionSheet控件的过程,包括自定义View和Fragment两种方法。首先从自定义View出发,创建MaskView和ActionSheet,实现了底部弹出菜单和点击事件监听。接着探讨了使用Fragment实现ActionSheet,通过declare-styleable读取自定义样式,并利用Builder模式简化构建过程。最后总结了ActionSheet的实现,提供了一种增强应用UI多样性的方法。
摘要由CSDN通过智能技术生成

## 《代码里的世界》UI篇

用文字札记描绘自己 android学习之路

转载请保留出处 by Qiao
http://blog.csdn.net/qiaoidea/article/details/46417747

【导航】


1.概述

  在讲述了弹出式对话框和对其 源码分析之后,我们尝试来模仿一下ios中常见的弹出式按钮选项——ActionSheet。其实样式也比较简单,从底部弹出几个按钮,提供选项菜单,同时出现半透明背景蒙版。具体详情及效果参考IOS设备。这里展示下我们最后实现的各种样式及效果图:
  
  仿IOS ActionSheet效果图
  


2.分析研究

  动手实现之前,先简单说两句。实现这个样式,具体要怎么做,能做成什么样,究竟该怎么用,到底好不好用?额,不知道,似乎都看你的编写技巧和封装了。鄙人愚笨,且写且摸索。
  当然先从熟悉的自定义View入手,使用一个线性布局LinearLayout嵌套N个Button实现。黑色半透明背景采用单独一个View,便于包装使用。做出最基本的效果之后,封装对外接口,用String[]数组来存取每个Button item的文本,并定义一个itemListener,设置监听item的点击事件。
  OK。完成这个并不难,如果我们想更进一层做好扩展,不妨尝试使用DialogFragment再做一遍,另外,前面还有提到AlertDialog中使用的Builder模式,我们也来做一下,看看效果如何。那么,为什么不更灵活一点儿,使用我们自定义的样式,可以切换ActionSheet风格,比如IOS6和IOS7?
  具体怎么做,来理下思路。首先继承自Fragment,在OnCreateView中实现自定义View,当然,在自定义View中使用我们的自定义属性,控制风格样式,另外呢,定义一个静态Builder类,负责设置数据与交互逻辑,最后通过Argument绑定到Fragment中去,实现最终效果。


3.详细实现

3.1 自定义View实现

  第一想法是用LinerLayout包指定个数的button,然后点击从底部弹出。然后设置背景变暗。后来发现其实用到黑色透明背景的地方貌似很多,弹窗,弹菜单,消息提示,几乎都是。
  因此这里先定义一个通用的MaskView,作用就是在窗体最前端弹出一个黑色半透明的遮罩蒙层。

1. MaskView黑色半透明蒙版

  MaskView全局变量

public class MaskView extends RelativeLayout {
   
    protected ViewGroup targetView; //将要添加到的目标view
    protected boolean isShowing; //是否显示
    protected long durationMillis; //显示动画持续时长
    protected boolean canCancel; //是否能点击外部隐藏 touchCancelOutside
    protected MaskListener maskListener; //点击事件

    //...

    public interface MaskListener {
    //点击事件监听接口
        void onShow();//显示
        void onHide();//隐藏
    }
 }

  构造方法和初始化。设置MaskView背景黑色,75%透明度,添加到目标view,并绑定点击事件。

public MaskView(Context context, ViewGroup targetView) {
        super(context);
        this.targetView = targetView;
        initialize();
    }

    protected void initialize() {
        setBackgroundColor(0x88000000);
        setVisibility(View.GONE);
        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        targetView.addView(this, lp);
        /**
        * 设置点击事件,如果可以点击空白区域隐藏,则点击隐藏
        */
        setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (canCancel) { 
                    hide();
                }
            }
        });
    }

  显示show()和隐藏hide()。使用透明动画AlphaAnimation,当动画结束执行相应监听事件。

 public void show() {
        if (isShowing)
            return;
        isShowing = true;
        clearAnimation();
        setVisibility(View.VISIBLE);
        AlphaAnimation an = new AlphaAnimation(0, 1);
        an.setDuration(durationMillis);
        startAnimation(an);
        if (maskListener != null)
            maskListener.onShow();
    }

    public void hide() {
        if (!isShowing)
            return;
        isShowing = false;
        clearAnimation();
        AlphaAnimation an = new AlphaAnimation(1, 0);
        an.setDuration(durationMillis);
        an.setAnimationListener(new AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                setVisibility(View.GONE);
            }
        });
        startAnimation(an);
        if (maskListener != null)
            maskListener.onHide();
    }
2. ActionSheet底部弹出菜单

  那么这里就打算做成一个RelativeLayout,包裹一个MaskView和一个LinearLayout,这个linearLayout就是前面说的菜单按钮集合了。
  打算做成什么样才能使我们调用方便?我期望是

final ActionSheet actionSheet = new ActionSheet(MainActivity.this);
        actionSheet.show("确定要退出么?",new String[]{
  "退出" },new Action1<Integer>(){
            @Override
            public void invoke(Integer index) {
                actionSheet.hide();
                if(index==0){
                    MainActivity.this.finish();
                }
            }
        });

  构造出来一个ActionSheet对象,然后显示的时候,显示

show(String title , String[] displayStrings, Action1 callback)

title 标题,
displayStrings 即各行item,
callback 回调,它传回的参数int表示第几个item被选中

  具体实现:
  ActionSheet 全局变量:

public class ActionSheet extends RelativeLayout {
   
    protected final static long durationMillis = 200;
    protected WindowManager windowManager;
    protected GestureDetector gestureDetector; //手势识别
    protected MaskView maskView; 
    protected LinearLayout actionSheetView;  //实际展示线性布局
    protected Button cancelButton; //取消按钮
    //...
}

  构造方法都执行initalize()实现初始化。首先绑定MaskView,添加显示/消失事件监听。接着初始化线性布局actionSheetView,默认不可见。位于视图底部并设置间距。其次,添加手势监听和按键监听,单点屏幕消失,按返回按钮消失。

    protected void initialize() {
        //初始化MaskView
        maskView = new MaskView(getContext(), this);
        maskView.setCanCancel(true);
        maskView.setDurationMillis(durationMillis);
        maskView.setOnMaskListener(new MaskListener() {
            @Override
            public void onShow() {
            }

            @Override
            public void onHide() {
                hide();
            }
        });

        //初始化线性布局容器actionSheetView
        actionSheetView = new LinearLayout(getContext());
        actionSheetView.setOrientation(LinearLayout.VERTICAL);
        actionSheetView.setVisibility(View.GONE);
        RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        rlp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE); //位于父View底部
        rlp.leftMargin = rlp.rightMargin = (int)applyDimension(getContext(), TypedValue.COMPLEX_UNIT_DIP, 8); //左右间距8dip
        addView(actionSheetView, rlp); //添加布局

        //初始化windowManager
        windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        //初始化手势识别事件,单点消失
        gestureDetector = new GestureDetector(getContext(), new SimpleOnGestureListener() {
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                hide();
                return super.onSingleTapUp(e);
            }
        });
        //初始化按键监听,按下返回则消失
        setOnKeyListener(new OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (KeyEvent.KEYCODE_BACK == keyCode && KeyEvent.ACTION_DOWN == event.getAction()) {
                    hide();
                    return true;
                }
                return false;
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值