复制Button控件时出现尺寸及位置异常问题求助
问题描述
- 复制原Button的LayoutParams后,新生成的Button尺寸仍不一致
- 使用
setBackground()方法会丢失波纹动画(Ripple animation) - 复制出的Button存在X坐标偏移
XML布局代码
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="coś tam" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.366" /> <FrameLayout android:id="@+id/Frame" android:layout_width="340dp" android:layout_height="519dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.491" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textView" app:layout_constraintVertical_bias="0.057"> <TextView android:id="@+id/Nazwa" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="0dp" android:text="Nazwa" /> <TextView android:id="@+id/godzinyOtwarcia" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="70dp" android:text="godziny otwarcia" /> <TextView android:id="@+id/ulica" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="35dp" android:text="ulica" /> <Button android:id="@+id/but" android:layout_width="100dp" android:layout_height="40dp" android:layout_marginTop="100dp" android:contextClickable="true" android:insetLeft="-13dp" app:layout_constraintStart_toStartOf="parent" android:insetTop="0dp" android:insetRight="-13dp" android:insetBottom="0dp" android:onClick="butClick" android:text="Szczegóły" android:textAlignment="center" android:textSize="14sp" app:rippleColor="#000000" /> </FrameLayout> </androidx.constraintlayout.widget.ConstraintLayout>
原复制逻辑代码
package com.example.aplikacjakolejna; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.RippleDrawable; import android.view.Gravity; import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.ScaleAnimation; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; import androidx.appcompat.app.AppCompatActivity; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.ConstraintSet; public class CreateFrame extends AppCompatActivity { private Context context; private ViewGroup parentLayout; public CreateFrame(Context context, ViewGroup parentLayout) { this.context = context; this.parentLayout = parentLayout; } public void LumpexCreateFrame(Button but){ // This is a constructor so the button is somewhere else... Button Newbut = new Button(context); Drawable buttonDrawable = Newbut.getBackground(); if (buttonDrawable instanceof RippleDrawable) { RippleDrawable rippleDrawable = (RippleDrawable) buttonDrawable; rippleDrawable.setColor(ColorStateList.valueOf(Color.parseColor("#FFFFFFFF"))); } Drawable buttonDrawable1 = but.getBackground(); if (buttonDrawable1 instanceof RippleDrawable) { RippleDrawable rippleDrawable = (RippleDrawable) buttonDrawable1; rippleDrawable.setColor(ColorStateList.valueOf(Color.parseColor("#FFFFFFFF"))); } Newbut.setBackground(buttonDrawable); but.setBackground(buttonDrawable1); Newbut.setText(but.getText()); Newbut.setTextColor(but.getCurrentTextColor()); Newbut.setTextSize(14); Newbut.setAllCaps(false); Newbut.setBottom(but.getBottom()); Newbut.setTop(but.getTop()); Newbut.setScaleX(but.getScaleX()); Newbut.setScaleY(but.getScaleY()); Newbut.setId(Lumpex.getId()); Newbut.setElevation(0f); Newbut.setStateListAnimator(null); Newbut.setGravity(but.getGravity()); Newbut.setMinimumHeight(but.getMinimumHeight()); Newbut.setBackgroundTintList(but.getBackgroundTintList()); Newbut.setLayoutParams(but.getLayoutParams()); Newbut.setPadding(but.getPaddingLeft(), but.getPaddingTop(), but.getPaddingRight(), but.getBottom()); parentLayout.addView(Newbut); Newbut.setX(but.getX()); Newbut.setY(but.getY()); Newbut.setTranslationY(Lumpex.getId() * 300 - 300); } }
解决方案
1. 保留波纹动画
直接复用原Button的背景实例并调用mutate(),避免多个Button共享同一背景样式导致的异常,同时不要替换原Button的背景:
// 替换原背景处理代码 Drawable originalBackground = but.getBackground().mutate(); Newbut.setBackground(originalBackground); Newbut.setBackgroundTintList(but.getBackgroundTintList()); Newbut.setRippleColor(but.getRippleColor());
2. 修复尺寸不一致问题
- 复制LayoutParams对象:不要直接复用原Button的LayoutParams,创建新的同类型LayoutParams实例,确保父布局是FrameLayout,使用
FrameLayout.LayoutParams:
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(but.getLayoutParams()); Newbut.setLayoutParams(params);
- 修正Padding设置:原代码中
setPadding最后一个参数错误使用but.getBottom(),替换为but.getPaddingBottom():
Newbut.setPadding(but.getPaddingLeft(), but.getPaddingTop(), but.getPaddingRight(), but.getPaddingBottom());
- 同步Inset属性:原Button设置了
insetLeft等属性,代码中需要同步:
Newbut.setInsetLeft(but.getInsetLeft()); Newbut.setInsetTop(but.getInsetTop()); Newbut.setInsetRight(but.getInsetRight()); Newbut.setInsetBottom(but.getInsetBottom());
3. 修复X坐标偏移问题
避免同时使用setLayoutParams和setX()/setY(),LayoutParams已控制View在父布局中的位置,setX()会叠加绝对偏移导致错位。仅用translationY调整垂直位置即可。
优化后的完整复制方法
public void LumpexCreateFrame(Button but){ Button Newbut = new Button(context); // 同步文本相关属性 Newbut.setText(but.getText()); Newbut.setTextColor(but.getCurrentTextColor()); Newbut.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); Newbut.setAllCaps(false); Newbut.setGravity(but.getGravity()); Newbut.setMinimumHeight(but.getMinimumHeight()); // 同步Inset属性 Newbut.setInsetLeft(but.getInsetLeft()); Newbut.setInsetTop(but.getInsetTop()); Newbut.setInsetRight(but.getInsetRight()); Newbut.setInsetBottom(but.getInsetBottom()); // 保留波纹动画的背景设置 Drawable originalBackground = but.getBackground().mutate(); Newbut.setBackground(originalBackground); Newbut.setBackgroundTintList(but.getBackgroundTintList()); Newbut.setRippleColor(but.getRippleColor()); // 复制LayoutParams,避免复用原对象 FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(but.getLayoutParams()); Newbut.setLayoutParams(params); // 同步Padding Newbut.setPadding(but.getPaddingLeft(), but.getPaddingTop(), but.getPaddingRight(), but.getPaddingBottom()); // 其他属性设置 Newbut.setId(Lumpex.getId()); Newbut.setElevation(0f); Newbut.setStateListAnimator(null); parentLayout.addView(Newbut); // 仅用translation调整垂直位置 Newbut.setTranslationY(Lumpex.getId() * 300 - 300); }
内容的提问来源于stack exchange,提问作者Koteczek Polski
相关产品推荐
相关产品推荐

