【问题标题】:How to move buttons text when state is pressed按下状态时如何移动按钮文本
【发布时间】:2011-12-02 09:10:36
【问题描述】:

我为按钮以及不同的按钮状态制作了自定义背景。但现在我提出了一个我无法理解的观点。

当按钮处于正常状态时,它看起来就很好。但是当我按下按钮时,我需要将文本向下移动几个像素,因为按钮背景图像在移动(实际上感觉就像它在图像上移动,因为首先在按钮下方有边框,当它处于按下状态时,这个边框就会消失)。请看下图。

当按钮状态被按下时,如何移动按钮中的按钮文本? (可能以某种方式填充或自定义按钮布局)

【问题讨论】:

  • 你可以试试这个3D按钮stackoverflow.com/a/19248175/2149195
  • 赏金附录:我现在尝试了一堆带有 9 个补丁的东西来移动文本内容。其中最有希望的看起来像android:variablePadding="true",但我仍然没有运气(是的,我尝试使触摸事件的视图无效......)

标签: android user-interface button


【解决方案1】:

在 9-patch 中设置填充对我不起作用。 在触摸监听器中设置填充很麻烦,会在任何使用按钮的地方乱扔代码。

我对@9​​87654321@ 进行了子类化,结果证明它相当整洁。就我而言,我想将图标(drawableLeft)和文本向左偏移 1px,向下偏移 1px。

子类按钮小部件:

package com.myapp.widgets;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Button;

import com.myapp.R;

public class OffsetButton extends Button {

    public OffsetButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public OffsetButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public OffsetButton(Context context) {
        super(context);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        boolean value = super.onTouchEvent(event);

        if (event.getAction() == MotionEvent.ACTION_UP) {
            setBackgroundResource(R.drawable.btn_normal);
        } else if (event.getAction() == MotionEvent.ACTION_DOWN) {
            setBackgroundResource(R.drawable.btn_pressed);
            setPadding(getPaddingLeft() + 1, getPaddingTop() + 1, getPaddingRight() - 1,
                    getPaddingBottom() - 1);
        }

        return value;
    }
}

并像这样在布局中使用它:

<com.myapp.widgets.OffsetButton
    android:text="@string/click_me"
    android:drawableLeft="@drawable/icon_will_be_offset_too_thats_good" />

几点说明:

  • 没有使用StateListDrawable 作为背景,而是在代码中切换背景。当我尝试使用StateListDrawable 时,填充更改和背景更改之间会有小的停顿。那看起来不太好。

  • 设置背景会重置填充,所以ACTION_UP情况下不需要调整填充

  • 增加顶部和左侧边距很重要,同时减少底部和右侧边距。所以内容区域的大小保持不变,内容区域实际上只是移动了。

【讨论】:

  • 确实感觉非常整洁的解决方案。会试一试。谢谢你的回答。
【解决方案2】:

我自己没有尝试过,但是如果您使用九个补丁作为两种状态的背景可绘制对象,那么您应该考虑在按下状态可绘制对象中设置适当的填充框。详情见here

【讨论】:

  • 我是否必须为按下的 9 补丁设置更多顶部填充?
  • 我会说是的。底部填充框部分应向右移动。
  • 我认为这是最好的方法,在代码中这样做很痛苦。
  • 这似乎对我不起作用。我正在调整内容与按钮区域移动的距离相同,但文本永远不会移动,按钮只是被拉伸得更大,以便文本同时满足按下和未按下状态。
【解决方案3】:

您可以在视图上使用填充。您可以将 OnTouchListener 添加到按钮或视图中

viewF.setOnTouchListener(new View.OnTouchListener() {  
    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
        if (event.getAction == MotionEvent.ACTION_UP) { 
            //set your padding            
        } else if (event.getAction == MotionEvent.ACTION_DOWN){
            //set your padding            
        }   
        return true; 
    } 
}); 

ontouchlistener 会在按下按钮时通知您。

【讨论】:

  • 正如我在之前的回答中所说。不是ontouchlistener,也不是gesture,也不是任何东西都可以给你按钮pressed。如果滚动按钮,您将获得您在ACTION_DOWN 中设置的填充。您甚至不会再收到 ACTION_UP 事件来将填充更改为默认值。 24k 声望和这样的回答。这是一种耻辱。我不是因为心情好就投反对票。
【解决方案4】:

Pēteris Caune 的答案比覆盖 setPressed() 效果更差。但是 setPressed 一切正常,直到您在 ICS 或更低的设备上测试您的应用程序并将按钮添加为列表视图项。 为了实现这一点,我改进了按钮的类:

public class OffsetButton extends Button {

    private static final int OFFSET_IN_DP = 6;
    private int offset_in_px;
    private boolean wasPressed = false;
    private Integer[] defaultPaddings;

    public OffsetButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView();
    }

    public OffsetButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public OffsetButton(Context context) {
        super(context);
        initView();
    }

    private void initView() {
        offset_in_px = (int) DisplayUtil.convertDpToPixel(OFFSET_IN_DP);
    }

    @Override
    public void setPressed(boolean pressed) {
        if (pressed && !wasPressed) {
            changePaddings();
        }
        if (!pressed && wasPressed) {
            resetPaddings();
        }
        super.setPressed(pressed);
    }

    private void changePaddings() {
        defaultPaddings = new Integer[]{getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom()};
        setPadding(getPaddingLeft(), getPaddingTop() + offset_in_px, getPaddingRight(), getPaddingBottom() - offset_in_px);
        wasPressed = true;
    }

    private void resetPaddings() {
        setPadding(defaultPaddings[0], defaultPaddings[1], defaultPaddings[2], defaultPaddings[3]);
        wasPressed = false;
    }

    @Override
    public boolean performClick() {
        resetPaddings();
        return super.performClick();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (isEnabled())
        {
            if (event.getAction() == MotionEvent.ACTION_DOWN && !wasPressed) {
                changePaddings();
            } else if (event.getAction() == MotionEvent.ACTION_UP && wasPressed) {
                resetPaddings();
            }
        }
        return super.onTouchEvent(event);
    }
}

【讨论】:

  • 当我在线性布局中并排有两个按钮时,我遇到了这个问题。即使添加的填充量与移除的填充量相同,按钮高度在按下期间也会发生变化,导致线性布局改变高度
  • 我为我的 LinearLayout 使用baselineAligned=false 修复了上述问题。在 onTouchEvent 中启用可能值得检查。
【解决方案5】:

这可能行得通:

setPadding(left, top, right, bottom); // Normal
setPadding(left, top + x, right, bottom - x); // Pressed

【讨论】:

  • @LASVEGAS 如何检测按钮何时处于按下状态?
  • 我猜你需要添加 View.OnTouchListener 并监听 MotionEvent.ACTION_DOWN
  • ...& 监听 MotionEvent.ACTION_DOWN。没你说的那么容易。对于固定按钮,它可以。但是当按钮滚动时会发生什么。 ACTION_DOWN NOT 与 xml 选择器中的 pressed state = true 相同。对于pressed state没有您可以抓住并做自己的事情。
猜你喜欢
  • 1970-01-01
  • 2021-12-20
  • 2015-01-10
  • 1970-01-01
  • 2012-06-11
  • 1970-01-01
  • 1970-01-01
  • 2021-03-20
  • 1970-01-01
相关资源
最近更新 更多