Android开发技巧——实现可复用的ActionSheet菜单

简介: 在上一篇《Android开发技巧——使用Dialog实现仿QQ的ActionSheet菜单》中,讲了这种菜单的实现过程,接下来将把它改成一个可复用的控件库。本文原创,转载请注明出处:http://blog.

在上一篇《Android开发技巧——使用Dialog实现仿QQ的ActionSheet菜单》中,讲了这种菜单的实现过程,接下来将把它改成一个可复用的控件库。

本文原创,转载请注明出处:

http://blog.csdn.net/maosidiaoxian/article/details/46324941

对于要实现的可复用的控件库,我需要它具备以下两点:

  1. 可添加远程依赖(不考虑Eclipse中的使用)
  2. 可灵活配置

分离库的实现代码

对于第一点,需要做的就是在Android Studio中新建一个library的module,然后把相关的实现代码,资源分离出来拖过去,并且把library中如图标,一些字符串等没有用到的资源删掉,保持AndroidManifest.xml的干净(仅保留会用到的权限,声明等)。在这里,我们library的AndroidManifest最终只剩下了:

<manifest
    package="com.githang.android.actionsheet">

    <application/>

</manifest>

注意,application节点里 的allowBackup属性要去掉,不然会让一些不知道怎么用tools中的几个属性来解决冲突的人,面对AndroidManifest.xml的合并冲突不知所措。labelicon属性在这里也不需要,所以也去掉了。

然后把一开始创建的app module的包名加上.demo后缀,把com.githang.andorid.actionsheet仅作为我们的library的包名(这个是纯属个人习惯,你也可以不这么做。我是觉得在包名上把library和demo区分来比较好,而我又不想给library加多一个.library的包。

分离完之后的项目是这样的:
https://github.com/msdx/ActionSheet/commit/934b73bc3e2d1504c9b13e87649ce388c59f4613

分离之后,就可以把我们的库打包成aar,并上传到jcenter,让别人能以添加远程依赖的方式来使用了。如何发布到jcenter,可以见我这篇博客:《使用Gradle发布Android开源项目到JCenter》

但是现在,我们仅完成的最基本的工作,因为,你不能要求每个人对一个库的要求都和你完全一样,可能有些人的需求中,需要改一下UI上的一些属性什么的。所以接下来,我们需要让我们的库能够灵活配置。

可自由配置的属性

我们的大部分属性是定义在xml中的。要改动这些属性,方法主要有两种:
1. 在Java代码中提供一些View的UI上的接口,让第三方通过调用它来设置。
2. 布局文件中使用属性的引用,而不是直接使用它的值。

如果你写的是自定义控件(通过继承View),那么你可能还需要自定义一些属性,让别人在使用的时候可以在xml中添加。由于这里我们写的不是这类控件,不需要用到它,在这里就不赘述了。

继续说上面的两种方法。Android中,采用xml定义布局,就是想让布局代码与逻辑代码相分离,所以第一种方式我是尽量少用的(在需要动态设置,或者是在Java代码中设置更简单时使用,)。下面先说一下第二种的方式的实现过程。

我们在xml中定义到的控件有三个,一是ListView,二是Button,三是ListView的Item。所以首先,在values文件夹里新建一个attrs.xml的属性文件,在里面分别定义三个属性,formatreference。如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="ActionSheetList" format="reference"/>
    <attr name="ActionSheetCancel" format="reference"/>
    <attr name="ActionSheetItem" format="reference"/>
</resources>

接着,把之前写的布局文件改为使用?attr的方式声明属性。

menu_item.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@android:id/text1"
          style="?attr/ActionSheetItem" />

dialog_action_sheet.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <ListView
        android:id="@+id/menu_items"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        style="?attr/ActionSheetList"
        android:listSelector="@android:color/transparent"/>

    <Button
        android:id="@+id/menu_cancel"
        style="?attr/ActionSheetCancel"/>
</LinearLayout>

然后在我们的style中声明这几个属性的style:

    <style name="ActionSheetList">
        <item name="android:divider">#c9dddddd</item>
        <item name="android:dividerHeight">1px</item>
    </style>
    <style name="ActionSheetItem">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">45dp</item>
        <item name="android:textSize">18sp</item>
        <item name="android:gravity">center</item>
        <item name="android:textColor">@color/menu_text</item>
    </style>
    <style name="ActionSheetCancel" parent="ActionSheetItem">
        <item name="android:layout_marginTop">8dp</item>
        <item name="android:layout_marginBottom">8dp</item>
        <item name="android:background">@drawable/menu_item_single</item>
    </style>

注意,这里的style的名称并不要求与attr中声明的名称一致,这里我只是懒得想其他名字,真的。

这样做了之后,其他人在使用的时候,会需要多一个步骤:在他的styler中的AppTheme(具体视androidmanifest中指定的theme而定)节点中,需要添加以下几项:

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="ActionSheetList">@style/ActionSheetList</item>
        <item name="ActionSheetItem">@style/ActionSheetItem</item>
        <item name="ActionSheetCancel">@style/ActionSheetCancel</item>
    </style>

如果他想自己修改属性的值,只需要写对应的style,然后把上面的item里的值改为他写的style即可。

对于菜单的改动,我们就改到这里。
接下来是对ActionSheetDialog的重构,让它提供可以进行以下设置的API:

  • 设置显示与隐藏时的动画
  • 设置菜单的背景

首先是菜单的背景,上文已经说过它一共有四个背景。所以定义一个菜单背景的类:

    /**
     * 菜单背景
     */
    public static class MenuBackground {
        public int top;
        public int middle;
        public int bottom;
        public int single;

        public MenuBackground() {}

        public MenuBackground(int top, int middle, int bottom, int single) {
            this.top = top;
            this.middle = middle;
            this.bottom = bottom;
            this.single = single;
        }
    }

然后定义一个菜单背景的对象,给它初始值,并定义一个设置背景的方法:

    private MenuBackground mMenuBg = new MenuBackground(R.drawable.menu_item_top,
            R.drawable.menu_item_middle, R.drawable.menu_item_bottom, R.drawable.menu_item_single);

    public void setMenuBackground(int top, int middle, int bottom, int single) {
        mMenuBg.top = top;
        mMenuBg.middle = middle;
        mMenuBg.bottom = bottom;
        mMenuBg.single = single;
    }

最后剩下动画的配置的。定义分别设置显示及隐藏动画的两个方法,注意,对隐藏动画的方法中,要设置动画结束的回调,在这里隐藏我们的菜单。

动画设置的代码重构如下:

    private void initAnim(Context context) {
        setShowAnimation(AnimationUtils.loadAnimation(context, R.anim.translate_up));
        setDismissAnimation(AnimationUtils.loadAnimation(context, R.anim.translate_down));
    }

    /**
     * @param animation Showing animation.
     * @since 0.2
     */
    public void setShowAnimation(Animation animation) {
        mShowAnim = animation;
    }

    /**
     * @param animation Dismissing animation.
     * @since 0.2
     */
    public void setDismissAnimation(Animation animation) {
        mDismissAnim = animation;
        mDismissAnim.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                dismissMe();
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
    }

现在我们的库已经重构完了,它暴露了适当的API,以让其他人可以自定义一些属性。它也对布局文件的配置提供了方法,即通过style来进行配置。

最后就是升版本号,改README,发布新版本了,打TAG了。

项目最后如下:
https://github.com/msdx/ActionSheet/tree/0.2

目录
相关文章
|
21天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
42 19
|
21天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
47 14
|
24天前
|
Java Linux 数据库
探索安卓开发:打造你的第一款应用
在数字时代的浪潮中,每个人都有机会成为创意的实现者。本文将带你走进安卓开发的奇妙世界,通过浅显易懂的语言和实际代码示例,引导你从零开始构建自己的第一款安卓应用。无论你是编程新手还是希望拓展技术的开发者,这篇文章都将为你打开一扇门,让你的创意和技术一起飞扬。
|
22天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
在数字时代,掌握安卓应用开发技能是进入IT行业的关键。本文将引导读者从零基础开始,逐步深入安卓开发的世界,通过实际案例和代码示例,展示如何构建自己的第一个安卓应用。我们将探讨基本概念、开发工具设置、用户界面设计、数据处理以及发布应用的全过程。无论你是编程新手还是有一定基础的开发者,这篇文章都将为你提供宝贵的知识和技能,帮助你在安卓开发的道路上迈出坚实的步伐。
31 5
|
21天前
|
开发框架 Android开发 iOS开发
安卓与iOS开发中的跨平台策略:一次编码,多平台部署
在移动应用开发的广阔天地中,安卓和iOS两大阵营各占一方。随着技术的发展,跨平台开发框架应运而生,它们承诺着“一次编码,到处运行”的便捷。本文将深入探讨跨平台开发的现状、挑战以及未来趋势,同时通过代码示例揭示跨平台工具的实际运用。
|
22天前
|
XML 搜索推荐 前端开发
安卓开发中的自定义视图:打造个性化UI组件
在安卓应用开发中,自定义视图是一种强大的工具,它允许开发者创造独一无二的用户界面元素,从而提升应用的外观和用户体验。本文将通过一个简单的自定义视图示例,引导你了解如何在安卓项目中实现自定义组件,并探讨其背后的技术原理。我们将从基础的View类讲起,逐步深入到绘图、事件处理以及性能优化等方面。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和技巧。
|
22天前
|
搜索推荐 前端开发 测试技术
打造个性化安卓应用:从设计到开发的全面指南
在这个数字时代,拥有一个定制的移动应用不仅是一种趋势,更是个人或企业品牌的重要延伸。本文将引导你通过一系列简单易懂的步骤,从构思你的应用理念开始,直至实现一个功能齐全的安卓应用。无论你是编程新手还是希望拓展技能的开发者,这篇文章都将为你提供必要的工具和知识,帮助你将创意转化为现实。
|
25天前
|
Java 调度 Android开发
安卓与iOS开发中的线程管理差异解析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自拥有独特的魅力。如同东西方文化的差异,它们在处理多线程任务时也展现出不同的哲学。本文将带你穿梭于这两个平台之间,比较它们在线程管理上的核心理念、实现方式及性能考量,助你成为跨平台的编程高手。
|
22天前
|
Java Android开发 开发者
探索安卓开发:构建你的第一个“Hello World”应用
在安卓开发的浩瀚海洋中,每个新手都渴望扬帆起航。本文将作为你的指南针,引领你通过创建一个简单的“Hello World”应用,迈出安卓开发的第一步。我们将一起搭建开发环境、了解基本概念,并编写第一行代码。就像印度圣雄甘地所说:“你必须成为你希望在世界上看到的改变。”让我们一起开始这段旅程,成为我们想要见到的开发者吧!
29 0
|
25天前
|
存储 监控 Java
探索安卓开发:从基础到进阶的旅程
在这个数字时代,移动应用已成为我们日常生活的一部分。对于开发者来说,掌握安卓开发不仅是技能的提升,更是通往创新世界的钥匙。本文将带你了解安卓开发的核心概念,从搭建开发环境到实现复杂功能,逐步深入安卓开发的奥秘。无论你是初学者还是有经验的开发者,这篇文章都将为你提供新的见解和技巧,帮助你在安卓开发的道路上更进一步。
20 0