Android实现View选中状态添加有动画效果的边框

Android实现View选中状态添加有动画效果的边框

首页休闲益智流动的线更新时间:2024-05-09
应用场景

最近开发了一个标签编辑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