最近开发了一个标签编辑APP,用户可以往编辑区域添加文本、条形码、二维码、图片等元素,然后对这些元素的位置、大小、内容等属性进行设置,最终设计出各种不同的标签界面。
标签编辑APP主界面
在编辑区中,当需要对某一个View元素调整属性参数时,首先要选中该View,让选中的View显示一个边框,以表示选中状态。例如上图中的那一串ID字符串,当选中这个元素后,给这个TextView添加了一个虚线边框。
添加了一个静态的边框后,为了达到更好的用户体验效果,我思考着给这个边框添加一个动画效果,很自然地联想到Photoshop处理图片时,那种选中区域轮廓上显示一个流动的虚线线条的效果。这也正是我希望达到的效果。
一番搜索之后,几乎没有找到有用的参考范例。静下心思考之后,Android中常用的渐变动画、帧动画、属性动画,貌似都无法实现这种想要的效果。在这个过程中,感觉最有可能的是SVG动画实现,但因为确实不熟悉这部分,因时间关系未做深究。
经过间断性地持续努力,找到了一种变通的做法,准确来说,这并不是动画,而是在观感上达到了想要实现的类似效果,并且,效果还不错。
下面,说一下我的实现方法。
添加边框首先,给View添加静态虚线边框,因为是选中状态的View才添加边框,即获得焦点或点击View之后,给该View添加一个边框,失去焦点时不显示边框。由此想到给View设置一个根据状态变化的background,即selector。
使用view_background.xml定义selector,selector中不同的状态定义不同的shape元素。代码如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<!-- 圆角边框 -->
<!--
<corners android:radius="1dp" />
-->
<!-- 虚线 -->
<stroke android:width="1.3dip"
android:color="#000000"
android:dashWidth="5dp"
android:dashGap="2dp"/>
<!-- 实线 -->
<!--
<stroke
android:width="1dp"
android:color="#0000FF" />
-->
<!-- padding -->
<padding android:top="2dp"
android:left="2dp"
android:right="2dp"
android:bottom="2dp" />
<!-- 设置矩形背景色 -->
<solid android:color="@android:color/transparent" />
</shape>
</item>
<item android:state_focused="true">
<shape android:shape="rectangle">
<!-- 圆角边框 -->
<!--
<corners android:radius="1dp" />
-->
<!-- 虚线 -->
<stroke android:width="1.3dip"
android:color="#000000"
android:dashWidth="5dp"
android:dashGap="2dp"/>
<!-- 实线 -->
<!--
<stroke
android:width="1dp"
android:color="#0000FF" />
-->
<!-- padding -->
<padding android:top="2dp"
android:left="2dp"
android:right="2dp"
android:bottom="2dp" />
<!-- 设置矩形背景色 -->
<solid android:color="@android:color/transparent" />
</shape>
</item>
<item android:state_focused="false">
<shape android:shape="rectangle">
<!-- 设置shape形状为矩形 -->
<!-- 圆角 -->
<!--
<corners android:radius="1dp" />
-->
<!-- padding -->
<padding android:top="2dp"
android:left="2dp"
android:right="2dp"
android:bottom="2dp" />
<!-- 设置矩形边框 -->
<stroke
android:width="0dp"
android:color="#000000" />
<!-- 设置矩形背景色 -->
<solid android:color="@android:color/transparent" />
</shape>
</item>
</selector>
在这个selector中,定义了矩形shape,矩形不填充颜色。当android:state_pressed为true或android:state_focused为true时,设置shape有边框线,当他们为false时,设置shape无边框线。
对于编辑区的所有View,都设置background为view_background.xml,这样便实现了View选中时有边框,失去焦点时无边框。
下一步,就是给这个边框添加“动画”效果了。
实现动画边框实现动画边框效果的思路,来自于我对虚线边框样式的调整过程中。我注意到上面定义的shape虚线边框中,可以通过改变android:dashWidth、android:dashGap两项参数,即虚线条的长度和虚线条之间的间隔宽度来改变虚线条的样式。
所以,我就想到了通过不断变换这两个参数,来实现边框展示出一种“动画”效果。
首先,我们需要知道,上面xml定义的selector,对应于Android API中的GradientDrawable,可以通过下面的方式将selector资源转换为GradientDrawable:
//将XML定义的selector资源加载为GradientDrawable对象
GradientDrawable gradientDrawable = (GradientDrawable)getDrawable(R.drawable.view_background);
然后,通过代码改变虚线条的长度和虚线条之间的间隔:
//setStroke方法可改变线条的粗细、颜色、虚线条的长度和虚线条之间的间隔
gradientDrawable.setStroke(width, color, dashWidth, dashGap);
GradientDrawable对象的setStroke方法,接收4个参数,分别表示线条的粗细、颜色、虚线条的长度和虚线条之间的间隔,如果dashWidth, dashGap都为0,则表示实线。
在我预期的效果中,线条的粗细、颜色都不变,只是改变dashWidth, dashGap这两个参数。
要实现边框的“动画”效果,需要不断地改变这两项参数。我分别定义了三组参数:
//定义3个不同的虚线条长度
private float[] dashwidth = new float[]{15F, 14F, 13F};
//定义3个不同的虚线条之间的间隔
private float[] dashGap = new float[]{3F, 2.8F, 2.6F};
如果需要变换线条颜色,也可以定义一组颜色:
//定义3个不同的颜色
private int[] strokeColor = new int[]{Color.parseColor("#FF0000"), Color.parseColor("#00FF00"), Color.parseColor("#0000FF")};
动态改变边框样式:
int BORDERStyleIndex = 0;
private Runnable borderChangeRunnable = new Runnable(){
@Override
public void run() {
if (selectedView != null) {
StateListDrawable drawable = (StateListDrawable)selectedView.getBackground();
GradientDrawable gradientDrawable = (GradientDrawable)drawable.getCurrent();
borderStyleIndex = (borderStyleIndex 1) % 3;
gradientDrawable.setStroke(4, strokeColor[borderStyleIndex], dashwidth[borderStyleIndex], dashGap[borderStyleIndex]);
selectedView.postDelayed(this, BORDER_STYLE_INTERVAL);
}
}
};
上面的selectedView表示当前选中的View。当View获取焦点或被点击后,只需这样调用:
//“动画”间的间隔时间
private static long BORDER_STYLE_INTERVAL = 600;
//改变选中View的边框
selectedView.postDelayed(borderChangeRunnable, BORDER_STYLE_INTERVAL);
这样,便实现了“动画”边框的效果。最初的预期的效果是虚线框看起来是一个顺时针流动的线条,这种实现方法与此有差距,不过通过微调上面定义的几组参数,在观感上可以达到近似的效果。
对于这一效果的实现,不知大家有没有更好的办法呢?
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved