Android小知识10则(下)

Android小知识10则(上) github传送门 注: 在目录中点击可以跳转到具体代码页

目录


Chronometer和CountDownTimer计时器

Android也是提供了计时器的, 虽然功能比较简单, 但是有些场景下也还是够用的...吗?(手动滑稽) CountDownTimer是倒计时计时器. Chronometer的话, 看怎么用了, 正着倒着都行...吗?(再次滑稽)

Chronometer的使用

礼貌性给下官方文档. 然后上效果图:

Chronometer的使用

mTimer.setBase(-60000 + SystemClock.elapsedRealtime());
mTimer.setCountDown(false);
mTimer.start();

我们以+1m(也就是从1分钟开始计时)为例:

  • 先看xml代码, android:format="%s"是要点, 后面会说. 然后它继承自TextView, 属性设置什么的就很简单了:
<Chronometer
    android:id="@+id/timer"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:layout_margin="@dimen/sixteen_dp"
    android:format="%s"
    android:textColor="@android:color/darker_gray"
    android:textSize="@dimen/thirty_sp" />

  • (-60000 + SystemClock.elapsedRealtime())的出现会让你一下子懵了, 所以先说SystemClock.elapsedRealtime(). Chronometer实例是需要设置基线的, 然后用SystemClock.elapsedRealtime()减去你设置的基线值, 换句话说, 如果你写mTimer.setBase(SystemClock.elapsedRealtime());就意味着从零开始. 然后单位是ms, 一分钟就是60000ms, 所以想从一分钟开始就是(-60000 + SystemClock.elapsedRealtime())了.
  • mTimer.setCountDown();代表是倒计时还是正常计时, false就是正常计时, true计时倒计时.
  • 你可能会提问, 为什么我没有格式化字符串它也正常显示了. 看xml中的android:format="%s", 这就是代表用默认的格式. 官方文档有这么一段: By default it will display the current timer value in the form "MM:SS" or "H:MM:SS", or you can use setFormat(String) to format the timer value into an arbitrary string. 也就是说默认"MM:SS", 超过1小时"H:MM:SS", 你可以用setFormat(String)设置你的style儿(手动滑稽).
  • 然后mTimer.start();是开始. mTimer.stop();是停止. 这很好理解了.

也许你会觉得它还挺好用, 但事实很残酷, 倒计时的功能要7.0才能使用, 其它的倒是兼容低版本, 但是废了一半了不是. 但是配合CountDownTimer, 意外地解决了麻烦.


CountDownTimer的使用

效果图:

CountDownTimer的使用

这个倒计时类异常好用. 构造函数第一个参数是总时长, 第二个是间隔. onTick是每次变化要执行的动作, onFinish是结束后要执行的动作. mCountDownTimer.start();是开始. mCountDownTimer.cancel();是停止. 完事了, 就这么多内容, 不信去看看官方文档.

private CountDownTimer mCountDownTimer = new CountDownTimer(10000, 1000) {

    @Override
    public void onTick(long millisUntilFinished) {
        String str = "剩余" + (millisUntilFinished / 1000) + "秒";
        mTvTime.setText(str);
    }

    @Override
    public void onFinish() {
        mTvTime.setEnabled(true);
        mTvTime.setText("倒计时结束");
    }
};

正则表达式

正则表达式是很通用的东西了, 不论写什么都会用到的, 看看应用中展现的部分正则表达式的功能吧:

正则表达式

  • 规则 只要知道了规则, 几乎没有正则表达式匹配不了的串(手动滑稽). 这里有个推荐的网站. 里面写的很细. 接下来展示如何在Android中实现的.
  • 匹配
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher("abcd1234ABCD5678");

上面两行是关键语句, compile方法中的字符串就是正则表达式, 这里是"\\d+"(注意多一个\是转义符). matcher方法中的字符串就是要匹配的字符串, 这里是"abcd1234ABCD5678". 然后有4种匹配方式, 我在效果图中展示的是find()matches():

序号

方法

说明

1

public boolean lookingAt()

尝试将从区域开头开始的输入序列与该模式匹配。

2

public boolean find()

尝试查找与该模式匹配的输入序列的下一个子序列。

3

public boolean find(int start)

重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列。

4

public boolean matches()

尝试将整个区域与模式匹配。

while (m.find()) {
    Log.i("sorrower", m.group());
}

上面的代码可以打印符合正则表达式的子序列结果. 当然你可以使用m.group(x)获取第x个匹配的子序列. 注意从1开始. 用m.start()和m.end()就可以获取到子序列的起始位置和结束位置后面一个位置了. matches()的返回值表示整个匹配是否成功.

  • 替换 除开匹配, 用正则表达式替换也是没问题的哦.

序号

方法

说明

1

public Matcher appendReplacement(StringBuffer sb, String replacement)

实现非终端添加和替换步骤。

2

public StringBuffer appendTail(StringBuffer sb)

实现终端添加和替换步骤。

3

public String replaceAll(String replacement)

替换模式与给定替换字符串相匹配的输入序列的每个子序列。

4

public String replaceFirst(String replacement)

替换模式与给定替换字符串匹配的输入序列的第一个子序列。

5

public static String quoteReplacement(String s)

返回指定字符串的字面替换字符串。这个方法返回一个字符串,就像传递给Matcher类的appendReplacement 方法一个字面字符串一样工作。


动态数组

来看看效果先吧!

动态数组

  • 转变为静态数组 首先是ArrayList转变为静态数组, 这个算是个小知识点吧, toArray方法中的参数要写对. 代码如下:
ArrayList<String> list = new ArrayList<>();
list.add("java");
list.add("c");
list.add("c++");
String[] strings = list.toArray(new String[0]);
Log.i("tag", Arrays.toString(strings));

  • 使用 使用起来也比较简单, 可以看官方文档, 或者看下我的源码, 改动改动体验下.

shape绘制

在没有UI设计师的时候, 或者是想简单看下效果的时候, 用shape进行快速绘制是极好的! 大家如果之前有关注我, 会知道这是之前一个单独的篇章, 当然不是为了凑数放在这里的, 和下一个知识点有关. 官方文档 一共有四种shape: rectangle, oval, line, ring.

矩形

我们一个一个来看, 首先是矩形:

矩形例子

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    
    <!-- 尺寸 -->
    <size
        android:width="160dp"
        android:height="80dp" />
    
    <!-- 颜色 -->
    <!--<solid android:color="@color/colorPrimary" />-->

    <!-- 内间距 -->
    <padding
        android:bottom="8dp"
        android:left="8dp"
        android:right="8dp"
        android:top="8dp" />

    <!-- 渐变 -->
    <gradient
        android:angle="45"
        android:endColor="@color/colorPrimary"
        android:startColor="@color/colorAccent"
        android:type="linear" />

    <!-- 圆角 -->
    <!--<corners android:radius="200dp" />-->

    <!-- 圆角单独设置 -->
    <corners
        android:bottomLeftRadius="0dp"
        android:bottomRightRadius="0dp"
        android:topLeftRadius="40dp"
        android:topRightRadius="40dp" />

    <!-- 描边 -->
    <stroke
        android:width="2dp"
        android:color="#666"
        android:dashGap="4dp"
        android:dashWidth="4dp" />
</shape>

  • 渐变gradient是会覆盖颜色的, 如果你想要纯色, 直接设置颜色值即可, 就是设置solid中的color.
  • 顺带一提, solid只有color一个参数.
  • 如果你没有渐变gradient, 也不写solid, 那么将会是空心的.
  • 渐变gradienttype参数有3个:
  • linear 线性渐变
  • sweep 扫描渐变
  • radial 放射渐变, 需要配合参数gradientRadius
  • 圆角corners可以直接设置radius, 也可以一个一个指定.
  • 描边stroke的话不写dashGap, dashWidth就会是实线, dashWidth代表虚线宽度, dashGap代表虚线间隔.
  • 内间距padding和尺寸size就不提了, 大家都懂的.

椭圆

椭圆例子

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

    <!-- 尺寸 -->
    <size
        android:width="160dp"
        android:height="80dp" />

    <!-- 颜色 -->
    <!--<solid android:color="@color/colorPrimary" />-->

    <!-- 内间距 -->
    <padding
        android:bottom="8dp"
        android:left="8dp"
        android:right="8dp"
        android:top="8dp" />

    <!-- 渐变 -->
    <gradient
        android:centerColor="@color/colorPrimary"
        android:endColor="@color/colorPrimaryDark"
        android:startColor="@color/colorAccent"
        android:type="sweep" />

    <!-- 描边 -->
    <stroke
        android:width="1dp"
        android:color="#333" />
</shape>

  • 渐变是最多可以设置三种颜色, 意思一看便知了:
  • startColor
  • centerColor
  • endColor
  • 一般椭圆都会用来绘制实心的小圆点.

线

线就很简单了:

线例子

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

    <!-- 描边 -->
    <stroke
        android:width="8dp"
        android:color="@color/colorPrimary"
        android:dashGap="8dp"
        android:dashWidth="6dp" />
</shape>

最后来看环, 它有些特有属性:

环例子B

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:innerRadiusRatio="4"
    android:shape="ring"
    android:thicknessRatio="100"
    android:useLevel="false">

    <!-- 尺寸 -->
    <size
        android:width="200dp"
        android:height="200dp" />

    <!-- 渐变 -->
    <gradient
        android:angle="0"
        android:centerColor="@color/colorPrimaryDark"
        android:endColor="@color/colorPrimary"
        android:startColor="@color/colorAccent"
        android:type="sweep" />

    <!-- 描边 -->
    <stroke
        android:width="1dp"
        android:color="#777"
        android:dashGap="4dp"
        android:dashWidth="4dp" />
</shape>

  • thicknessRatio 指的是环厚度百分比, 默认是9, 比如说这里宽度是200dp, thicknessRatio是100, 环厚度就是200dp / 100 = 2dp. 当然, 你可以直接用thickness设置厚度.
  • innerRadiusRatio 是内环百分比, 默认是3, 就是指用宽度 / 百分比得到的值就是内环半径. 同样可以用innerRadius直接设置.

用shape绘制SeekBar

我知道有很多非常好看的自定义进度条, 但是我写这个SeekBar是想补充下shape的使用, 用非常少量的代码实现自定义进度条. 来看看效果图:

用shape绘制SeekBar

  • 实现
<SeekBar
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/eight_dp"
    android:max="200"
    android:maxHeight="@dimen/eight_dp"
    android:minHeight="@dimen/eight_dp"
    android:progressDrawable="@drawable/layout_progress"
    android:thumb="@drawable/shape_circle" />

简单解释下几个要点属性:

  • max代表进度条最大的值.
  • maxHeight, minHeight可以设置进度条宽度, 我喜欢稍微宽一点的.
  • thumb设置滑块, 可以是图片, 可以是shape写的设置.
  • progressDrawable代表进度条的外观, 可以是图片, 可以是shape写的设置.

再来看看滑块和进度条外观具体代码, 进度条可以设置背景, 进度, 和第二进度. 滑块的话, 你想画成什么样都行.

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background">
        <shape>
            <corners android:radius="@dimen/four_dp" />
            <solid android:color="@android:color/darker_gray" />
        </shape>
    </item>
    <item android:id="@android:id/secondaryProgress">
        <clip>
            <shape>
                <corners android:radius="@dimen/four_dp" />
                <solid android:color="@color/colorAccent" />
            </shape>
        </clip>
    </item>
    <item android:id="@android:id/progress">
        <clip>
            <shape>
                <corners android:radius="@dimen/four_dp" />
                <solid android:color="@android:color/holo_blue_light" />
            </shape>
        </clip>
    </item>
</layer-list>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="@android:color/holo_blue_light" />
    <stroke
        android:width="@dimen/one_dp"
        android:color="@android:color/holo_blue_light" />
    <size
        android:width="@dimen/sixteen_dp"
        android:height="@dimen/sixteen_dp" />
</shape>

java部分的话, 用Handler实例postDelayed方法让进度条跑起来就可以看到效果了. 这里设定50ms发一次消息.

findViewById(R.id.cv_start).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (mRunnable == null) {
            mRunnable = new MyRunnable();
            mHandler.postDelayed(mRunnable, 0);
        }
    }
});

findViewById(R.id.cv_stop).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mHandler.removeCallbacks(mRunnable);
        mRunnable = null;
    }
});
private class MyRunnable implements Runnable {
    @Override
    public void run() {
        int progress = mSbTest.getProgress();
        mTvProgress.setText(String.valueOf(progress));
        mSbTest.setProgress(++progress);
        mSbTest.setSecondaryProgress(progress + 10);

        int progress2 = mSbTest2.getProgress();
        mTvProgress2.setText(String.valueOf(progress2));
        mSbTest2.setProgress(++progress2);
        mSbTest2.setSecondaryProgress(progress2 + 20);

        mHandler.postDelayed(this, 50);
    }
}

最后

这样就写完10个知识点了, 这样之后很多文章扩展起来就会很方便了. 喜欢记得点赞, 有意见或者建议评论区见, 暗中关注我也是可以的哦~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

Golang语言--slice 切片原理

golang 中的 slice 非常强大,让数组操作非常方便高效。在开发中不定长度表示的数组全部都是 slice 。但是很多同学对slice 的模糊认识,造成认...

40590
来自专栏前端迷

头条秋招面试题以及答案

答案: 定义 3D 转换,只是用 Z 轴的值。 拓展: transform 属性向元素应用 2D 或 3D 转换。该属性允许我们对元素进行旋转、缩放、移动或倾斜...

14030
来自专栏前端小叙

vue路由跳转报错解决

20140
来自专栏冰霜之地

深入解析 Go 中 Slice 底层实现

切片是 Go 中的一种基本的数据结构,使用这种结构可以用来管理数据集合。切片的设计想法是由动态数组概念而来,为了开发者可以更加方便的使一个数据结构可以自动增加和...

18830
来自专栏Golang语言社区

转--每周一个GoLang设计模式之组合模式

GoF在第二章通过设计一个Lexi的文档编辑器来介绍设计模式的使用,GoF认为Lexi设计面临七个问题: 1. **文档结构**2. **格式化**3. **修...

36160
来自专栏图形学与OpenGL

CG实验6 交互与动画

(1) 示范代码1为交互实例:在鼠标点击的位置上绘制出点;示范代码2为动画实例:三角形按照恒定的速度(45度/秒)旋转。结合示范代码,学习理解交互与动画的基本思...

14410
来自专栏木子昭的博客

Javascript常用API备忘录

Bom常见API 获取浏览器信息 var ua = navigator.userAgent if (ua.indexOf('Chrome')){ co...

32630
来自专栏小筱月

关于 vue 不能 watch 数组变化 和 对象变化的解决方案

再如使用 splice(0, 2, 3) 从数组下标 0 删除两个元素,并在下标 0 插入一个元素 3:

1.7K30
来自专栏前端小叙

js操作DOM在父元素中的结尾添加子节点注意

所以js是不能直接传入字符串的,但是jquery的append可以直接传入html字符串。

20840
来自专栏申龙斌的程序人生

零基础学编程031:Python与其它语言最不同的一条语法规则

有C或JAVA其它编程语言基础的人可能对Python中的这条语法规则最不适应:Python中的缩进是有语法含义的,它用来表示一个代码块(code block)。...

32050

扫码关注云+社区

领取腾讯云代金券