Android Spinner OnItemSelected仅用于用户交互

问题描述 投票:2回答:2

我知道这个问题已被多次回答,但我没有发现它们中的任何一个令人满意,当然也不优雅。

问题是OnItemSelected不仅在用户选择项目时被触发,而且在以编程方式设置选择时也会被触发。

一些答案建议在程序员为微调器设置值时设置一个标志。但有时其他Android代码会将值设置在代码之外。

android设置值的常见位置是实例化微调器。一些答案解决了这一特定问题。但是,有很多地方会破坏Android并重新实现微调器。追踪所有这些并不优雅。

所以问题是:如何将他们的OnItemSelectedListener代码仅附加到用户与UI交互所做的选择?

  • Spinner.setOnItemClickListener似乎可以完美地回答这个问题,但谷歌已将其禁用
  • AdapterView.setOnClickListener似乎也是一个自然的候选者,但它也会产生运行时错误

接下来的地方是扩展Spinner并开始重写方法,但这当然意味着搞乱API(我宁愿不去做,或者我至少想让其他用户和我一起工作)

android spinner user-interaction onitemselectedlistener
2个回答
2
投票

所以我发布了一个答案,但欢迎任何批评,改进或其他更优雅的答案。

关键是重写onClick以设置一个标志,该标志将onItemSelectedListener与用户交互联系起来并触发onItemClickedListener。

如果您觉得使用API​​ setOnItemClickedListener感觉不舒服(可能是为了将来兼容),您当然可以替换自己的方法。我只觉得onItemClickedListener应该已经实现了这个效果,所以这是我的微妙抗议。

此外,如果有人能够想到spinnerTouched标志被短路的原因(保持真实的时间超过它应该),请告诉我们以便解决。到目前为止它似乎工作得很好。

public class OnItemClickSpinner extends Spinner implements AdapterView.OnItemSelectedListener {

    boolean spinnerTouched = false;
    OnItemClickListener onItemClickListener = null;
    OnItemSelectedListener onItemSelectedListener = null;

    public OnItemClickSpinner(Context context) {
        super(context);
        super.setOnItemSelectedListener(this);
    }

    public OnItemClickSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
        super.setOnItemSelectedListener(this);
    }

    public OnItemClickSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        super.setOnItemSelectedListener(this);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        spinnerTouched = true;
        return super.onTouchEvent(event);
    }

    @Override
    public void setOnItemClickListener(OnItemClickListener listener) {
        onItemClickListener = listener;
    }

    @Override
    public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener) {
        this.onItemSelectedListener = onItemSelectedListener;
        super.setOnItemSelectedListener(this);
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        if(spinnerTouched && this.onItemClickListener!=null) this.onItemClickListener.onItemClick(parent,view,position,id);
        if(this.onItemSelectedListener!=null) this.onItemSelectedListener.onItemSelected(parent,view,position,id);
        spinnerTouched=false;
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {
        if(this.onItemSelectedListener!=null) this.onItemSelectedListener.onNothingSelected(parent);
        spinnerTouched=false;
    }
}

0
投票

iOS中的某些UI组件存在类似问题。我决定使用类似的黑客。

所以在拥有微调器的对象中的某个地方 - 可能是一个活动 - 声明一个成员变量:private var isSelectionFromTouch: Boolean = false

其余的相关代码:

init {
    spinner.onItemSelectedListener = this
    spinner.setOnTouchListener { _, _ ->
        this.isSelectionFromTouch = true
        false
    }
}

// On Item Selected

override
fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
    if (!isSelectionFromTouch) { return }
    Log.d(TAG, "item selected. do something.")
    isSelectionFromTouch = false
}

override
fun onNothingSelected(parent: AdapterView<*>?) {
    isSelectionFromTouch = false
}
© www.soinside.com 2019 - 2024. All rights reserved.