乌市泽哥 发表于 2025-4-18 09:15:05

Android三种onClick实现方式具体对比

https://i-blog.csdnimg.cn/direct/069318ad74634762b229978a86e48c72.png


https://i-blog.csdnimg.cn/direct/0da0de89d5d24432a5cf49bceb230735.png
第一种方式:静态内部类 + 转达View参数

实今世码

Button btn_toMain2 = findViewById(R.id.btn_toMain2);
btn_toMain2.setOnClickListener(new staticMyOnClickListener(tv_hello));

static class staticMyOnClickListener implements View.OnClickListener{
    private final TextView tv_hello;

    public staticMyOnClickListener(TextView tv_hello) {
      this.tv_hello = tv_hello;
    }

    @Override
    public void onClick(View view) {
      tv_hello.setTextColor(0xFFFF0000);
    }
}
特点与优劣

优点:

[*]内存安全:使用静态内部类,不会隐式持有外部Activity的引用
[*]职责明确:点击逻辑封装在独立类中,符合单一职责原则
[*]可复用:可以在多个地方复用同一个ClickListener
缺点:

[*]代码量较多:必要单独定义类
[*]参数转达贫苦:如果必要访问多个Activity成员,必要全部通过构造函数转达
[*]不敷灵活:修改TextView必要重新创建实例
适用场景:


[*]处置惩罚相对独立、简单的点击逻辑
[*]必要复用点击逻辑的情况
[*]对内存安全性要求较高的场景
第二种方式:非静态内部类(示例代码有误,应为非静态)

修正后的实今世码

Button btn_toMain3 = findViewById(R.id.btn_toMain3);
btn_toMain3.setOnClickListener(new MyOnClickListener());

class MyOnClickListener implements View.OnClickListener{
    @Override
    public void onClick(View view) {
      // 可以直接访问Activity成员
      tv_hello.setTextColor(0xFFFF0000);
    }
}
特点与优劣

优点:

[*]访问方便:可以直接访问外部Activity的全部成员
[*]代码简便:不必要转达参数
[*]实现简单:适合快速开发
缺点:

[*]内存走漏风险:非静态内部类隐式持有Activity引用,如果被长生命周期对象持有会导致内存走漏
[*]复用性差:与特定Activity强耦合,难以复用
适用场景:


[*]简单的临时点击处置惩罚
[*]确定生命周期短、不会被外部持有的情况
[*]必要频繁访问Activity成员的场景
第三种方式:Activity实现接口

实今世码

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      
      Button btn_toMain5 = findViewById(R.id.btn_toMain5);
      btn_toMain5.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
      if(view.getId() == R.id.btn_toMain5){
            Intent intent = new Intent();
            intent.setClass(this, MainActivity5.class);
            startActivity(intent);
      }
    }
}
特点与优劣

优点:

[*]代码集中:全部点击逻辑在一个方法中,便于管理
[*]内存安全:不会造成内存走漏
[*]适合多控件:适合处置惩罚多个控件的点击事件
[*]简便:不必要额外定义类
缺点:

[*]方法易膨胀:当控件多时,onClick方法会变得巨大
[*]耦合度高:点击逻辑与Activity强耦合
[*]可读性降落:大量if-else或switch-case降低可读性
适用场景:


[*]处置惩罚少量控件的点击事件
[*]必要快速实现点击功能的场景
[*]点击逻辑相对简单的应用
综合对比表

特性静态内部类非静态内部类Activity实现接口内存安全性高低(有走漏风险)高代码量多中等少复用性高低低访问Activity成员需显式转达直接访问直接访问适合控件数量单个/少量单个/少量多个代码组织分散分散集中保举程度★★★★☆★★☆☆☆★★★☆☆ 现实开发发起


[*] 优先考虑Lambda表达式(Java 8+):
button.setOnClickListener(v -> {
    // 处理点击
});
简便且内存安全,适合简单逻辑
[*] 复杂逻辑使用静态内部类:

[*]特殊是必要复用的场景
[*]或者点击逻辑较复杂必要单独封装的

[*] 避免使用非静态内部类:

[*]除非能确保不会造成内存走漏
[*]或者点击逻辑生命周期与Activity完全同等

[*] Activity实现接口适合:

[*]小型项目或快速原型开发
[*]点击逻辑简单且控件不多的情况

[*] 对于大型项目:

[*]考虑使用ViewBinding或DataBinding
[*]或者接纳MVVM模式,将点击逻辑放在ViewModel中

Android 按钮点击与长按事件共存及状态控制

一、点击和长按事件并存且互不干扰的实现方法

1. 尺度实现方式(保举)

Button myButton = findViewById(R.id.my_button);

// 点击事件
myButton.setOnClickListener(v -> {
    if (!isLongPress) { // 添加标志位判断
      Log.d("ButtonEvent", "正常点击事件触发");
      // 点击事件处理逻辑
    }
});

// 长按事件
myButton.setOnLongClickListener(v -> {
    Log.d("ButtonEvent", "长按事件触发");
    isLongPress = true;
    // 长按事件处理逻辑
   
    // 延迟重置标志位
    new Handler().postDelayed(() -> isLongPress = false, 300);
    return true; // 必须返回true表示消费事件
});

// 类成员变量
private boolean isLongPress = false;
关键点:


[*]onLongClickListener必须返回true,体现已消费事件,阻止点击事件触发
[*]使用标记位isLongPress作为额外保障
[*]延迟重置标记位避免快速连续操纵的问题
2. 使用时间阈值判断

private long lastEventTime;

myButton.setOnTouchListener((v, event) -> {
    switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN:
            lastEventTime = System.currentTimeMillis();
            break;
      case MotionEvent.ACTION_UP:
            if (System.currentTimeMillis() - lastEventTime < 500) {
                Log.d("ButtonEvent", "点击事件");
            }
            break;
    }
    return false;
});

myButton.setOnLongClickListener(v -> {
    Log.d("ButtonEvent", "长按事件");
    return true;
});
3. 高级方案:GestureDetector

class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
      Log.d("ButtonEvent", "点击事件");
      return true;
    }

    @Override
    public void onLongPress(MotionEvent e) {
      Log.d("ButtonEvent", "长按事件");
    }
}

// 在Activity中:
GestureDetector gestureDetector = new GestureDetector(this, new MyGestureListener());

myButton.setOnTouchListener((v, event) -> {
    gestureDetector.onTouchEvent(event);
    return true;
});
二、按钮可用状态控制方法

1. 根本状态设置

// 禁用按钮
myButton.setEnabled(false);

// 启用按钮
myButton.setEnabled(true);

// 检查按钮状态
boolean isEnabled = myButton.isEnabled();
2. 可视化状态反馈

<!-- res/drawable/button_state.xml -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_enabled="false" android:drawable="@drawable/btn_disabled" />
    <item android:state_enabled="true" android:drawable="@drawable/btn_enabled" />
</selector>
// 应用状态drawable
myButton.setBackgroundResource(R.drawable.button_state);

// 同时改变文字颜色
myButton.setTextColor(getResources().getColorStateList(R.color.button_text_color));
3. 使用Alpha透明度体现禁用状态

myButton.setEnabled(false);
myButton.setAlpha(0.5f); // 半透明效果

myButton.setEnabled(true);
myButton.setAlpha(1.0f); // 恢复不透明
4. 综合状态管理类

public class ButtonStateManager {
    public static void disableButton(Button button) {
      button.setEnabled(false);
      button.setAlpha(0.5f);
      button.setTextColor(Color.GRAY);
    }
   
    public static void enableButton(Button button) {
      button.setEnabled(true);
      button.setAlpha(1.0f);
      button.setTextColor(Color.BLACK);
    }
}

// 使用示例
ButtonStateManager.disableButton(myButton);
5. 使用DataBinding(高级)

<Button
    android:enabled="@{viewModel.isButtonEnabled}"
    android:onClick="@{() -> viewModel.onButtonClick()}"
    android:backgroundTint="@{viewModel.isButtonEnabled ? @color/active : @color/inactive}" />
三、最佳实践发起


[*] 事件处置惩罚选择:

[*]简单场景:使用尺度setOnClickListener+setOnLongClickListener组合
[*]复杂手势:使用GestureDetector
[*]精确控制:使用OnTouchListener手动处置惩罚事件

[*] 状态控制发起:

[*]禁用按钮时一定要提供视觉反馈
[*]考虑使用StateListDrawable管理不同状态
[*]禁用状态下应阻止全部交互事件

[*] 性能优化:

[*]避免在频繁调用的方法中操纵按钮状态
[*]对多个按钮的状态管理考虑使用同一工具类

[*] 用户体验:

[*]长按时间发起保持在400-600ms之间
[*]禁用按钮时可以添加Tooltip说明缘故原由
if (!myButton.isEnabled()) {
    myButton.setTooltipText("请先完成上一步操作");
}

通过以上方法,可以实现按钮点击和长按事件的完善共存,并灵活控制按钮的各种状态。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Android三种onClick实现方式具体对比