最近公司让做一个语音识别的功能,基本效果如下图:
看上去很简单的一张图,但是发现里边的坑实在不少.
首先,我们先分析下这个按钮:
- 最外边是一个灰色的线性布局1
- 里边是一个带有状态选择器的线性布局2
- 线性布局2里边是一个带有状态选择器的imageview和textview
下边我们先给这个线性布局设置selector
selector
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/shape_voice_unpressed" android:state_enabled="false"></item>
<item android:drawable="@drawable/shape_voice_pressed" android:state_enabled="true"></item>
</selector>
布局
<LinearLayout
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_margin="20dp"
android:background="@drawable/selector_voice_circleboard2"
android:gravity="center"
android:orientation="horizontal">
</LinearLayout>
这个时候发现:给LinearLayout设置的selector,点击后没有反应感觉很奇怪,到网上查了查,给的解决方案是添加这么一句话:
android:clickable="true"
添加上之后果然问题解决了,可是为什么会这样呢?
Log.d("TAG", "rl_root是否可点击?==" + rl_root.isClickable());
打印的结果:
04-10 16:55:46.860 11124-11124/com.gelitenight.waveview.sample D/TAG: rl_root是否可点击?==false
也就是说默认情况下:
LinearLayout是不可点击的,不可点击的按钮自然没有android:state_pressed这个状态,添加了android:clickable=”true”或者点击事件就可以响应状态选择器中的android:state_pressed状态
3.下边我们再看我们这里不单单要让外边的LinearLayout有状态选择器,还要让里边的imageview和
textview都有状态选择器:
<LinearLayout
android:id="@+id/ll_btn_voice"
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="@drawable/selector_voice_circleboard2"
android:clickable="true"
android:gravity="center"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_btn_voice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/selector_voice_btn2"/>
<TextView
android:id="@+id/tv_btn_voice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" 按住 说出你要的商品"
android:textColor="@color/selector_voice_textcolor2"
android:textSize="16sp"/>
</LinearLayout>
这里只需要给外边的LinearLayout设置一个android:clickable=”true”就可以使LinearLayout和里边的
Imageview和textview的selector都生效,但是到网上找的相关的说法是,给每个子控件添加:
android:duplicateParentState="true"
这个属性的作用:
如果设置此属性,将直接从父容器中获取绘图状态(光标,按下等)。 注意仅仅是获取绘图状态,而没有获取事件,也就是你点一下LinearLayout时Button有被点击的效果,但是不执行点击事件
然而,我发现:
只要给外边的LinearLayout设置一个android:clickable=”true”就可以达到效果,里边的Imageview和textview添加或者不添加 android:duplicateParentState=”true”,并没有什么影响.
4.最终要求的这个按钮不仅要点击后颜色状态的变化,还需要向上滑动取消录音
也就是说:需要给这个LinearLayout设置OnTouchListener
private int downY;
ll_voice_btn_content2.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = (int) event.getRawY();
break;
case MotionEvent.ACTION_UP:
int upY = (int) event.getRawY();
if (Math.abs(upY - downY) > 20) {
Toast.makeText(TestSelectorActivity.this, "停止录音", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
return true;
}
});
设置上去发现:刚才的状态选择器失效了,原因是因为设置了OnTouchListener后,OnTouchListener会将事件抢过来,那么要想同时实现滑动取消和状态选择器只能在代码中,动态的去设置按下的状态:setPressed(true),
不过,个人习惯性性试验setEnabled(true),下边是部分代码:
布局文件:
<LinearLayout
android:id="@+id/ll_voice_btn_content2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#ededed"
android:orientation="horizontal"
android:paddingBottom="10dp"
android:paddingLeft="25dp"
android:paddingRight="25dp"
android:paddingTop="10dp">
<LinearLayout
android:id="@+id/ll_btn_voice2"
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="@drawable/selector_voice_circleboard"
android:enabled="false"
android:gravity="center"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/iv_btn_voice2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
android:src="@drawable/selector_voice_btn"/>
<TextView
android:id="@+id/tv_btn_voice2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:enabled="false"
android:text=" 按住 说出你要的商品"
android:textColor="@color/selector_voice_textcolor"
android:textSize="16sp"
/>
</LinearLayout>
</LinearLayout>
MainActivity:
public class MainActivity extends Activity {
@ViewInject(R.id.ll_voice_btn_content2)
private LinearLayout ll_voice_btn_content2;
@ViewInject(R.id.ll_btn_voice2)
private LinearLayout ll_btn_voice2;
@ViewInject(R.id.iv_btn_voice2)
private ImageView iv_btn_voice2;
@ViewInject(R.id.tv_btn_voice2)
private TextView tv_btn_voice2;
@ViewInject(R.id.rl_root)
private RelativeLayout rl_root;
private int downY;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_selector);
ViewUtils.inject(this);
Log.d("TAG", "rl_root是否可点击?==" + rl_root.isClickable());
ll_btn_voice2.setEnabled(false);
iv_btn_voice2.setEnabled(false);
tv_btn_voice2.setEnabled(false);
ll_voice_btn_content2.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = (int) event.getRawY();
ll_btn_voice2.setEnabled(true);
iv_btn_voice2.setEnabled(true);
tv_btn_voice2.setEnabled(true);
break;
case MotionEvent.ACTION_UP:
ll_btn_voice2.setEnabled(false);
iv_btn_voice2.setEnabled(false);
tv_btn_voice2.setEnabled(false);
int upY = (int) event.getRawY();
if (Math.abs(upY - downY) > 20) {
Toast.makeText(TestSelectorActivity.this, "停止录音", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
return true;
}
});
}
}