分类
English 原创作品 技术 移动互联网

泡面管家Android 3.0版发布 – Instant Noodles Master for Android 3.0 Released

泡面管家:界面清新、操作便捷,专为泡面优化的一键计时器
Instant Noodles Master: One-Tap-Timer for Instant Noodles, refreshing design, convenient to use.

high-res_icon_baidu-64

最新版本 Latest Version

3.0 – 全新《泡面管家》,将成为你最称心的泡面计时器。
3.0 – Brand new NoodlesMaster, now is your best timer app for cooking instant noodles.

1_Screenshot_2014-08-31-21-06-162_Screenshot_2014-08-31-21-05-53

最近更新 Recent changes

  • 预定义多组泡面时间,更提供了便于操作的小部件(Widget),以及到时提醒功能。
    Predefined durations, convenient widgets, on-time notifications.
  • 全新扁平化设计(flat design),风格贴近安卓4.0+的Halo主题。
    New flat design based on Android 4.0+ Halo theme.
  • 仍然支持Android 2.2+的老设备。
    Still supporting Android 2.2+.
  • 增加了诸如条码扫描、在线购买,以及分享至微博等贴心功能。
    Adding interesting features like barcode scan, buy online, and share to SNS.

4_Screenshot_2014-08-31-21-06-565_Screenshot_2014-08-31-21-09-14

应用下载 App Download

从豌豆荚安装 Install from Wandoujia:

WandoujiaWandoujia

或从谷歌Play市场安装 Or install from Google Play:

Install from Google Play

应用介绍 App Introduction

《泡面管家》(NoodlesMaster)是一款面向泡面(方便面、速食面、即食面)爱好者的小工具。
Instant Noodles Master (i.e. NoodlesMaster) is a small tool for instant noodles funs.

主要功能:
Features:

  • 泡面计时
    Timer for instant noodles
  • 泡面条码扫描识别
    Barcode scan
  • 在线购买泡面
    Buy noodles online
  • 分享至微博
    Share to SNS (now support Weibo)

新版中强化了泡面计时器的功能,并支持扫码识别、在线购买泡面、分享到微博,力求成为最便捷的泡面计时器。
The new version of NoodlesMaster enhanced the timer feature for instant noodles, also introduced barcode scan, buy online and share to SNS features, aims to be your best mate when cooking instant noodles.

用户可以点击主界面底部任一按钮开始计时,《泡面管家》会在到达指定时限时提示用户。上部圆形计时表盘在计时过程中,点击正中间的按钮会停止计时。用户也可以向手机主屏添加快捷启动计时的小部件。
A user may tap any button at the bottom of the main interface to kick off the timer, NoodlesMaster will notify user when timer completes. During timer runs, user may tap the stop button in the center of the top ring to cancel the timer. User may also add shortcut widgets onto home screen, which can start the timer by only one tap.

6_device-2013-05-11-204352

官方网站Official Website: http://n.evis.me

欢迎您提出宝贵意见,bug或新功能建议请在官方网站留言。
Any bugs or new feature requests, please feel free to reach me at above official website, or submit to: http://code.google.com/p/noodlesmaster/issues/list

feature_graphic-en-US

前一版本介绍:
Previous version:

泡面管家Android 2.1版发布 – Instant Noodles Master for Android 2.1 Released

分类
English 原创作品 技术 移动互联网

泡面管家Android版开源 – Instant Noodles Master for Android Is Open Souce

专为泡面开发的一键计时器《泡面管家》Android版已开放源代码,并托管于GitHub上。
The One-Tap-Timer for instant noodles, Instant Noodles Master for Android, is now open source on GitHub.

开源项目URL是:
The URL of the open souce project is:

https://github.com/evisong/noodlesmaster

源代码早于2010年已托管在GoogleCode上,于2013年7月迁移至GitHub,原GoogleCode源代码将不再维护。
The souce code is originally hosted on GoogleCode since 2010, and was finally migrated to GitHub on July 2013, since then the copy on GoogleCode will no longer be maintained.

分类
原创作品 技术 移动互联网

Android开发:用Drawable XML绘制带阴影效果的圆形按钮

众所周知,在Android开发里,为了优化在各种分辨率设备上的显示效果,同一份图片素材往往要提供mdpi、hdpi、xhdpi三种(以前还有ldpi),尤其是按钮类的素材,考虑到normal、pressed、focused更是需要至少3×3=9张图片。NinePatch技术虽然可以解决一部分尺寸灵活性的问题,但大部分修改和适配还是要再次制作一批图片的。

根据交互设计的需要,可以考虑用Drawable的XML绘制按钮,好处有:

  • 矢量绘制,易于缩放;
  • 字节数更少(一般而言);
  • 基于XML文本,属性值易于调整;
  • Drawable组件间可嵌套,可重用;
  • XML与项目其他源代码在一起,便于版本控制。

当然也有缺点:

  • 没有可视化的编辑器,编辑不够直观;
  • 受限于基本的图形和填充方式;
  • 美工人员很难上手。

以本站开发的习作《泡面管家》(参见这里)为例。

下图是泡面管家的计时器,中间的圆形(包含镂空阴影效果)默认是表示计时器状态的icon,在计时器运行期间会变换为停止计时的按钮:

noodlesmaster_timer

这里icon的背景是用Drawable XML绘制的。在Android中,Drawable XML并不支持阴影,参考了网上诸多例子,一般都是以额外绘制的渐变或者边框来实现阴影。这里是用叠加shape的方式来绘制的。

noodlesmaster_timer_zoom

上图中绿色方框中的标识的色块,从外到内可以划分成几个部分:

  1. Outer circle
  2. Inner shadow of outer circle
  3. Gap
  4. Outer shadow of center circle
  5. Center circle

使用<layer-list/>,从最底层开始,画对应最外部分的、最大的圆形,然后逐层的、边扩大padding边叠加圆形,圆形的填充颜色要对应到相应的色块。res/drawable/timer_center_bg.xml代码如下:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- outer circle -->
    <item>
        <shape android:shape="oval" >
            <solid android:color="#FFACB8C3" />
        </shape>
    </item>

    <!-- inner shadow of outer circle -->
    <item
        android:bottom="2dp"
        android:left="2dp"
        android:right="2dp"
        android:top="2dp">
        <shape android:shape="oval">
            <solid android:color="#FFbdcad6" />
        </shape>
    </item>
    <item
        android:bottom="3dp"
        android:left="3dp"
        android:right="3dp"
        android:top="3dp">
        <shape android:shape="oval">
            <solid android:color="#FFc3cfd9" />
        </shape>
    </item>
    <item
        android:bottom="4dp"
        android:left="4dp"
        android:right="4dp"
        android:top="4dp">
        <shape android:shape="oval">
            <solid android:color="#FFcbd6df" />
        </shape>
    </item>
    <item
        android:bottom="5dp"
        android:left="5dp"
        android:right="5dp"
        android:top="5dp">
        <shape android:shape="oval">
            <solid android:color="#FFd4dee5" />
        </shape>
    </item>

    <!-- gap -->
    <item
        android:bottom="6dp"
        android:left="6dp"
        android:right="6dp"
        android:top="6dp">
        <shape android:shape="oval" >
            <solid android:color="#FFdae2e8" />
        </shape>
    </item>

    <!-- outer shadow of center circle -->
    <item
        android:bottom="10dp"
        android:left="10dp"
        android:right="10dp"
        android:top="10dp">
        <shape android:shape="oval">
            <solid android:color="#FFced5dc" />
        </shape>
    </item>
    <item
        android:bottom="12dp"
        android:left="12dp"
        android:right="12dp"
        android:top="12dp">
        <shape android:shape="oval">
            <solid android:color="#FFbcc4c9" />
        </shape>
    </item>
    <item 
        android:bottom="13dp"
        android:left="13dp"
        android:right="13dp"
        android:top="13dp">
        <shape android:shape="oval">
            <solid android:color="#FFb4bbc0" />
        </shape>
    </item>
    <item 
        android:bottom="14dp"
        android:left="14dp"
        android:right="14dp"
        android:top="14dp">
        <shape android:shape="oval">
            <solid android:color="#FFacb3b8" />
        </shape>
    </item>

    <!-- center circle -->
    <item
        android:bottom="15dp"
        android:left="15dp"
        android:right="15dp"
        android:top="15dp">
        <shape android:shape="oval">
            <stroke android:width="1dp" android:color="#FFFCFCFC"/>
            <gradient
                android:angle="270"
                android:endColor="#FFCFD7DD"
                android:startColor="#FFF0F5F9" />
        </shape>
    </item>

</layer-list>

从以上代码中可以看出,只是简单的圆形的叠加,就可以绘制出具有立体感的按钮。

要注意上边只是按钮的背景。文章开头也讲过,Drawable XML的特征之一就是可复用。继续看res/drawable/stop_timer_btn.xml的代码:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- normal -->
    <item android:state_enabled="true" android:state_focused="false" android:state_pressed="false">
        <layer-list>
            <item android:drawable="@drawable/timer_center_bg" />
            <item android:bottom="15dp" android:left="15dp" android:right="15dp" android:top="15dp">
                <shape android:shape="oval">
                    <stroke android:width="1dp" android:color="#FFFCFCFC" />
                    <gradient android:angle="270" android:endColor="#FF91c0e8" android:startColor="#FFa7d3fa" />
                </shape>
            </item>
        </layer-list>
    </item>

    <!-- pressed -->
    <item android:state_enabled="true" android:state_pressed="true">
        <layer-list>
            <item android:drawable="@drawable/timer_center_bg" />
            <item android:bottom="15dp" android:left="15dp" android:right="15dp" android:top="15dp">
                <shape android:shape="oval">
                    <stroke android:width="2dp" android:color="#FFf8f640" />
                    <gradient android:angle="270" android:endColor="#FF91c0e8" android:startColor="#FFa7d3fa" />
                </shape>
            </item>
        </layer-list>
    </item>

    <!-- selected -->
    <item android:state_enabled="true" android:state_focused="true" android:state_pressed="false">
        <layer-list>
            <item android:drawable="@drawable/timer_center_bg" />
            <item android:bottom="15dp" android:left="15dp" android:right="15dp" android:top="15dp">
                <shape android:shape="oval">
                    <stroke android:width="2dp" android:color="#FFf8f640" />
                    <gradient android:angle="270" android:endColor="#FF91c0e8" android:startColor="#FFa7d3fa" />
                </shape>
            </item>
        </layer-list>
    </item>

    <!-- ...... -->
</selector>

上述代码以看出,<selector/>中每个<item/>都是一个<layer-list/>,将@drawable/timer_center_bg作为背景在前景叠加圆形以区分不同状态。

最后要说明的是,决定一个按钮应该是否用Drawable XML渲染,应考虑以下几个因素:

  • App是否要支持多分辨率;
  • App是否有瘦身的需要;
  • 图案是否足够简单;
  • 图案需要自由缩放;
  • 设计开发工作流程是否容许开发人员跨界;
  • 开发人力相对于设计人力更充足。

否则,应该考虑以图片方式渲染。