测试了Android 5.0.1和 Android 6.0.1机器上面都有这个问题。
布局代码:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.zhangyinshan.framelayouttest.MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAlignment="center"
android:text="Hello World!"
android:id="@+id/hello"
android:textSize="26sp" />
<TextView
android:id="@+id/up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/holo_red_light"
android:text="UP"
android:textSize="26sp"
android:layout_gravity="center"
android:textAlignment="center"
/>
</FrameLayout>
这个是因为Android 5.0之后引入了一个Material Design的概念:
https://developer.android.com/training/material/shadows-clipping.html?hl=zh-cn
视图的 Z值包含两个组件:
- 高度(Elevation):静态组件。Elevation
- 转换(Translation):用于动画的动态组件。
Z = elevation + translationZ
这里TranslationZ就是指的在Z轴上面的转换,注意转换,主要是用于动画的动态的组件,例如Button,它在按下去的时候是0dp的高度,正常的状态下是6dp的高度。所以Z = elevation + translationZ;
在MainActivity中执行测试:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button button = (Button)findViewById(R.id.hello);
//设置触摸监听
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
//当当前的android 的版本大于21,也就是5.0以上的时候,去检测Elevation 和TranslationZ
if(Build.VERSION.SDK_INT>=21) {
switch (motionEvent.getAction()){
case MotionEvent.ACTION_DOWN:
Log.d("kodulf", "按下去的时候 Elevation="+button.getElevation() + " TranslationZ=" + button.getTranslationZ());
break;
case MotionEvent.ACTION_UP:
Log.d("kodulf", "弹上来的时候 Elevation="+button.getElevation() + " TranslationZ=" + button.getTranslationZ());
break;
}
}
return false;
}
});
}
}
结果:
03-30 22:57:21.191 17218-17218/com.example.framelayouttest D/kodulf: 按下去的时候 Elevation=3.0 TranslationZ=0.0
03-30 22:57:21.364 17218-17218/com.example.framelayouttest D/kodulf: 弹上来的时候 Elevation=3.0 TranslationZ=6.0
03-30 22:57:22.517 17218-17218/com.example.framelayouttest D/kodulf: 按下去的时候 Elevation=3.0 TranslationZ=0.0
03-30 22:57:22.915 17218-17218/com.example.framelayouttest D/kodulf: 弹上来的时候 Elevation=3.0 TranslationZ=6.0
从结果可以看出:
在Android 5.0 之后的版本中,按钮Button 都会有一个TranslationZ的值,默认的没有点击的时候是6dp,如果点击了按下去了就是0dp
解决办法:
1: 给最上面的TextView设置一个TranslationZ或者是Elevation设置一个高的值,这个值要比上面测试的结果6+3=9大,就是至少10
就是上面的公式:Z = elevation + translationZ
这里TextView的Z值一定要比Button的Z值要大
android:elevation="10dp" android:translationZ="10dp"
2: 将Button的动画的StateListAnimation设置为null,因为如果将Button的StateListAnimation 取消了Translation就会变成0了
android:stateListAnimator="@null"
解决办法1实例:
可以在xml布局中设置,也可以在代码中设置
在xml中设置:给最上面的TextView设置elevation或者设置translationZ,只要设置一个就可以了,两个都设置也可以的
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.zhangyinshan.framelayouttest.MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAlignment="center"
android:text="Hello World!"
android:id="@+id/hello"
android:textSize="26sp" />
<TextView
android:id="@+id/up"
android:elevation="10dp"
android:translationZ="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/holo_red_light"
android:text="UP"
android:textSize="26sp"
android:layout_gravity="center"
android:textAlignment="center"
/>
</FrameLayout>
在代码中设置:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button button = (Button)findViewById(R.id.hello);
final TextView upTextView = (TextView)findViewById(R.id.up);
//如果android 的版本大于21,也就是5.0以上的时候,去设置Elevation 和TranslationZ
if(Build.VERSION.SDK_INT>21) {
upTextView.setElevation(10);
upTextView.setTranslationZ(10);
}
//每一秒钟检测一次
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
//当当前的android 的版本大于21,也就是5.0以上的时候,去检测Elevation 和TranslationZ
if(Build.VERSION.SDK_INT>=21) {
switch (motionEvent.getAction()){
case MotionEvent.ACTION_DOWN:
Log.d("kodulf", "Button按下去的时候 Elevation="+button.getElevation()
+ " TranslationZ=" + button.getTranslationZ()
+" Z = Elevation+TranslationZ = "+(button.getElevation()+button.getTranslationZ()));
Log.d("kodulf","Button按下去的时候 upTextView Z = "
+ " TranslationZ=" + upTextView.getTranslationZ()
+" Z = Elevation+TranslationZ = "+(upTextView.getElevation()+upTextView.getTranslationZ()));
break;
case MotionEvent.ACTION_UP:
Log.d("kodulf", "Button弹上来恢复的时候 Elevation="+button.getElevation()
+ " TranslationZ=" + button.getTranslationZ()
+" Z = Elevation+TranslationZ = "+(button.getElevation()+button.getTranslationZ()));
Log.d("kodulf","Button弹上来恢复的时候 upTextView Z="
+ " TranslationZ=" + upTextView.getTranslationZ()
+" Z = Elevation+TranslationZ = "+(upTextView.getElevation()+upTextView.getTranslationZ()));
break;
}
}
return false;
}
});
}
}
结果:
03-30 23:41:51.633 29545-29545/com.example.framelayouttest D/kodulf: Button按下去的时候 Elevation=3.0 TranslationZ=0.0 Z = Elevation+TranslationZ = 3.0
03-30 23:41:51.634 29545-29545/com.example.framelayouttest D/kodulf: Button按下去的时候 upTextView Z = TranslationZ=10.0 Z = Elevation+TranslationZ = 20.0
03-30 23:41:51.734 29545-29545/com.example.framelayouttest D/kodulf: Button弹上来恢复的时候 Elevation=3.0 TranslationZ=5.6289196 Z = Elevation+TranslationZ = 8.62892
03-30 23:41:51.735 29545-29545/com.example.framelayouttest D/kodulf: Button弹上来恢复的时候 upTextView Z= TranslationZ=10.0 Z = Elevation+TranslationZ = 20.0
解决办法2实例:
将Button的动画的StateListAnimation设置为null,因为如果将Button的StateListAnimation 取消了Translation就会变成0了,也分为布局中设置和代码中设置
android:stateListAnimator="@null"
布局中设置:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.zhangyinshan.framelayouttest.MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textAlignment="center"
android:text="Hello World!"
android:id="@+id/hello"
android:stateListAnimator="@null"
android:textSize="26sp" />
<TextView
android:id="@+id/up"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/holo_red_light"
android:text="UP"
android:textSize="26sp"
android:layout_gravity="center"
android:textAlignment="center"
/>
</FrameLayout>
代码中:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button button = (Button)findViewById(R.id.hello);
final TextView upTextView = (TextView)findViewById(R.id.up);
//如果android 的版本大于21,也就是5.0以上的时候,设置button的stateAnimator为null
if(Build.VERSION.SDK_INT>21) {
button.setStateListAnimator(null);
}
//如果android 的版本大于21,也就是5.0以上的时候,去设置Elevation 和TranslationZ
// if(Build.VERSION.SDK_INT>21) {
// upTextView.setElevation(10);
// upTextView.setTranslationZ(10);
// }
//每一秒钟检测一次
button.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
//当当前的android 的版本大于21,也就是5.0以上的时候,去检测Elevation 和TranslationZ
if(Build.VERSION.SDK_INT>=21) {
switch (motionEvent.getAction()){
case MotionEvent.ACTION_DOWN:
Log.d("kodulf", "Button按下去的时候 Elevation="+button.getElevation()
+ " TranslationZ=" + button.getTranslationZ()
+" Z = Elevation+TranslationZ = "+(button.getElevation()+button.getTranslationZ()));
Log.d("kodulf","Button按下去的时候 upTextView Z = "
+ " TranslationZ=" + upTextView.getTranslationZ()
+" Z = Elevation+TranslationZ = "+(upTextView.getElevation()+upTextView.getTranslationZ()));
break;
case MotionEvent.ACTION_UP:
Log.d("kodulf", "Button弹上来恢复的时候 Elevation="+button.getElevation()
+ " TranslationZ=" + button.getTranslationZ()
+" Z = Elevation+TranslationZ = "+(button.getElevation()+button.getTranslationZ()));
Log.d("kodulf","Button弹上来恢复的时候 upTextView Z="
+ " TranslationZ=" + upTextView.getTranslationZ()
+" Z = Elevation+TranslationZ = "+(upTextView.getElevation()+upTextView.getTranslationZ()));
break;
}
}
return false;
}
});
}
}
结果:
03-30 23:50:32.682 9981-9981/com.example.framelayouttest D/kodulf: Button按下去的时候 Elevation=0.0 TranslationZ=0.0 Z = Elevation+TranslationZ = 0.0
03-30 23:50:32.682 9981-9981/com.example.framelayouttest D/kodulf: Button按下去的时候 upTextView Z = TranslationZ=0.0 Z = Elevation+TranslationZ = 0.0
03-30 23:50:32.804 9981-9981/com.example.framelayouttest D/kodulf: Button弹上来恢复的时候 Elevation=0.0 TranslationZ=0.0 Z = Elevation+TranslationZ = 0.0
03-30 23:50:32.804 9981-9981/com.example.framelayouttest D/kodulf: Button弹上来恢复的时候 upTextView Z= TranslationZ=0.0 Z = Elevation+TranslationZ = 0.0
参考:Button always displays on top in FrameLayout