You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

复制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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 12:35:57