像华为可左右扩展手机-HUAWEI Mate30Pro 举例
关闭左右扩展后,屏幕左右会留出24px的宽度
此时setX实际上华为会自动增加24px值,setX导致向右偏移了24px
【解决方法】
获取根ViewGroup距离屏幕左侧距离,像这样,但不能再OnCreate后立即获取,需要延迟获取
int[] location = new int[2];
roomRoot.getLocationOnScreen(location);
在setX时,最终再减去 location[0] 值即可
有些折叠手机、平板亦是如此
获取根ViewGroup距离屏幕左侧距离,像这样,但不能再OnCreate后立即获取,需要延迟获取。此时setX实际上华为会自动增加24px值,setX导致向右偏移了24px。像华为可左右扩展手机-HUAWEI Mate30Pro 举例。关闭左右扩展后,屏幕左右会留出24px的宽度。在setX时,最终再减去。
android:layout_width="200dp"
android:layout_height="50dp"
android:layout_marginLeft="20dp"
android:text="Test"/>
看一下原图:
然后我们调一下setX看看:
上面的那张图很好的说明了每个方法获得的坐标值或者距离都是从哪里到哪里的。说明一下,图中有三个黑色的框框,最外层的是手机屏幕,中间层的是ViewGroup,最内层的是ViewGroup中放置的view。 其实上图中标注的方法可以分为两类,一类是View提供的方法,一类是MotionEvent提供的方法。分别说明如下:
View提供的获取的坐标以及距离的方法:getTop() 获取到
要实现一个气泡动画,并且不可以超出屏幕,可以使用 ValueAnimator 类和 View 的 layout 参数。以下是一个简单的示例代码,可以让一个气泡在屏幕中进行弹跳动画:
MainActivity.java:
public class MainActivity extends AppCompatActivity {
private ImageView bubble;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bubble = findViewById(R.id.bubble);
ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
animator.setDuration(2000);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
float x = calculateX(value);
float y = calculateY(value);
bubble.setX(x);
bubble.setY(y);
animator.start();
private float calculateX(float value) {
// 计算 x 坐标
float x = value * 500; // 500 是屏幕的宽度
if (x < bubble.getWidth() / 2) {
return bubble.getWidth() / 2;
if (x > 500 - bubble.getWidth() / 2) {
return 500 - bubble.getWidth() / 2;
return x;
private float calculateY(float value) {
// 计算 y 坐标
float y = (float) (400 * Math.sin(value * Math.PI));
if (y < bubble.getHeight() / 2) {
return bubble.getHeight() / 2;
if (y > 800 - bubble.getHeight() / 2) {
return 800 - bubble.getHeight() / 2;
return y;
在这个示例中,我们创建了一个 ValueAnimator 对象,设置了动画时间为 2 秒,插值器为 LinearInterpolator(线性插值器),然后添加了一个动画更新监听器,在监听器中计算出当前时间点的 x 和 y 坐标,并将其应用到 ImageView 上。在 calculateX() 方法中,我们简单地将 x 坐标设置为时间的线性函数,这将导致气泡水平移动。但是,我们还需要确保气泡不会超出屏幕范围,因此我们使用了一些条件语句来限制气泡的位置。在 calculateY() 方法中,我们使用正弦函数来计算出 y 坐标,这将导致气泡上下移动,并产生弹跳的效果。同样,我们使用条件语句来确保气泡不会超出屏幕范围。最后,我们使用 start() 方法启动动画。