1

У меня есть пользовательский виджет, который имеет четкую кнопку, установленную как правую, используя метод setCompoundDrawablesWithIntrinsicBounds(). Теперь мне нужно добавить ошибки в виджет, и я попытался использовать стандартные функции и полагаться на метод setError().EditText setCompoundDrawablesWithIntrinsicBounds() не работает после setError()

Проблема, с которой я столкнулась, заключается в том, что после того, как я установил ошибку, мое правое выделение не будет отображаться снова, даже если я снова его установлю.

Неужели кто-нибудь столкнулся с этой проблемой и, возможно, нашел решение проблемы?

спасибо.

LE: Я забыл упомянуть, что если я использую setError("My error hint text", null) вместо setError("Please choose an valid destination!"), все будет хорошо, но, как вы можете догадаться, значок ошибки не будет отображаться.

LLE: Это мой пользовательский класс, который обрабатывает отображение значка очистки и действия для него.

/** 
* Class of {@link android.widget.AutoCompleteTextView} that includes a clear (dismiss/close) button with a 
* OnClearListener to handle the event of clicking the button 
* <br/> 
* Created by ionut on 26.04.2016. 
*/ 
public class ClearableAutoCompleteTextView extends AppCompatAutoCompleteTextView implements View.OnTouchListener { 

    /** 
    * The time(in milliseconds) used for transitioning between the supported states. 
    */ 
    private static final int TRANSITION_TIME = 500; 

    /** 
    * Flag for hide transition. 
    */ 
    private static final int TRANSITION_HIDE = 101; 

    /** 
    * Flag for show transition. 
    */ 
    private static final int TRANSITION_SHOW = 102; 

    /** 
    * Image representing the clear button. (will always be set to the right of the view). 
    */ 
    @DrawableRes 
    private static int mImgClearButtonRes = R.drawable.ic_clear_dark; 

    /** 
    * Task with the role of showing the clear action button. 
    */ 
    private final Runnable showClearButtonRunnable = new Runnable() { 
     @Override 
     public void run() { 
      Message msg = transitionHandler.obtainMessage(TRANSITION_SHOW); 
      msg.sendToTarget(); 
     } 
    }; 

    /** 
    * Task with the role of hiding the clear action button. 
    */ 
    private final Runnable hideClearButtonRunnable = new Runnable() { 
     @Override 
     public void run() { 
      Message msg = transitionHandler.obtainMessage(TRANSITION_HIDE); 
      msg.sendToTarget(); 
     } 
    }; 

    /** 
    * Flag indicating if the default clear functionality should be disabled. 
    */ 
    private boolean mDisableDefaultFunc; 
    // The default clear listener which will clear the input of any text 
    private OnClearListener mDefaultClearListener = new OnClearListener() { 
     @Override 
     public void onClear() { 
      getEditableText().clear(); 
      setText(null); 
     } 
    }; 

    /** 
    * Touch listener which will receive any touch events that this view handles. 
    */ 
    private OnTouchListener mOnTouchListener; 

    /** 
    * Custom listener which will be notified when an clear event was made from the clear button. 
    */ 
    private OnClearListener onClearListener; 

    /** 
    * Transition drawable used when showing the clear action. 
    */ 
    private TransitionDrawable mTransitionClearButtonShow = null; 

    /** 
    * Transition drawable used when hiding the clear action. 
    */ 

    private TransitionDrawable mTransitionClearButtonHide = null; 

    private AtomicBoolean isTransitionInProgress = new AtomicBoolean(false); 

    private final Handler transitionHandler = new Handler(Looper.getMainLooper()) { 
     @Override 
     public void handleMessage(Message msg) { 
      switch (msg.what) { 
       case TRANSITION_HIDE: 
        setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); 
        isTransitionInProgress.set(false); 
        break; 
       case TRANSITION_SHOW: 
        setCompoundDrawablesWithIntrinsicBounds(0, 0, mImgClearButtonRes, 0); 
        isTransitionInProgress.set(false); 
        break; 
       default: 
        super.handleMessage(msg); 
      } 
     } 
    }; 

    /* Required methods, not used in this implementation */ 
    public ClearableAutoCompleteTextView(Context context) { 
     super(context); 
     init(); 
    } 

    /* Required methods, not used in this implementation */ 
    public ClearableAutoCompleteTextView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
     init(); 
    } 

    /* Required methods, not used in this implementation */ 
    public ClearableAutoCompleteTextView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     init(); 
    } 

    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
     if (getCompoundDrawables()[2] == null) { 
      // Pass the touch event to other listeners, if none, the normal flow is resumed 
      return null != mOnTouchListener && mOnTouchListener.onTouch(v, event); 
     } 

     // React only when the UP event is detected 
     if (event.getAction() != MotionEvent.ACTION_UP) { 
      return false; 
     } 

     // Detect the clear button area of touch 
     int x = (int) event.getX(); 
     int y = (int) event.getY(); 
     int left = getWidth() - getPaddingRight() - getCompoundDrawables()[2].getIntrinsicWidth(); 
     int right = getWidth(); 
     boolean tappedX = x >= left && x <= right && y >= 0 && y <= (getBottom() - getTop()); 
     if (tappedX) { 
      // Allow clear events only when the transition is not in progress 
      if (!isTransitionInProgress.get()) { 
       if (!mDisableDefaultFunc) { 
        // Call the default functionality only if it wasn't disabled 
        mDefaultClearListener.onClear(); 
       } 

       if (null != onClearListener) { 
        // Call the custom clear listener so that any member listening is notified of the clear event 
        onClearListener.onClear(); 
       } 
      } 
     } 

     // Pass the touch event to other listeners, if none, the normal flow is resumed 
     return null != mOnTouchListener && mOnTouchListener.onTouch(v, event); 
    } 

    @Override 
    public void setOnTouchListener(OnTouchListener l) { 
     // Instead of using the super, we manually handle the touch event (only one listener can exist normally at a 
     // time) 
     mOnTouchListener = l; 
    } 

    private void init() { 
     // Set the bounds of the button 
     setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); 
     if (getCompoundDrawablePadding() == 0) { 
      // We want to have some default padding, in case no one is specified in the xml 
      setCompoundDrawablePadding(Dimensions.dpToPx(getContext(), 5f)); 
     } 
     enableTransitionClearButton(); 

     // if the clear button is pressed, fire up the handler. Otherwise do nothing 
     super.setOnTouchListener(this); 
    } 

    @Override 
    public void onRestoreInstanceState(Parcelable state) { 
     super.onRestoreInstanceState(state); 
     updateClearButton(); 
    } 

    @Override 
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { 
     super.onTextChanged(text, start, lengthBefore, lengthAfter); 
     updateClearButton(); 
    } 

    /** 
    * When hiding/showing the clear button an transition drawable will be used instead of the default drawable res. 
    */ 
    public void enableTransitionClearButton() { 
     mTransitionClearButtonShow = 
       (TransitionDrawable) ContextCompat.getDrawable(getContext(), R.drawable.ic_clear_fade_in); 
     mTransitionClearButtonHide = 
       (TransitionDrawable) ContextCompat.getDrawable(getContext(), R.drawable.ic_clear_fade_out); 
     mTransitionClearButtonShow.setCrossFadeEnabled(true); 
     mTransitionClearButtonHide.setCrossFadeEnabled(true); 
    } 

    /** 
    * When hiding/showing the clear button the default drawable res will be used instead of the transition drawable. 
    */ 
    @SuppressWarnings("unused") 
    public void disableTransitionClearButton() { 
     mTransitionClearButtonShow = null; 
     isTransitionInProgress.set(false); 
     transitionHandler.removeCallbacks(hideClearButtonRunnable); 
     transitionHandler.removeCallbacks(showClearButtonRunnable); 
    } 

    /** 
    * Set an custom listener which will get notified when an clear event was triggered from the clear button. 
    * 
    * @param clearListener 
    *   The listener 
    * @param disableDefaultFunc 
    *   {@code true} to disable the default clear functionality, usually meaning it will be 
    *   handled by the 
    *   calling member. {@code false} allow the default functionality of clearing the input. 
    * 
    * @see #setOnClearListener(OnClearListener) 
    */ 
    public void setOnClearListener(final OnClearListener clearListener, boolean disableDefaultFunc) { 
     this.onClearListener = clearListener; 
     this.mDisableDefaultFunc = disableDefaultFunc; 
    } 

    /** 
    * Set an custom listener which will get notified when an clear event was triggered from the clear button. 
    * 
    * @param clearListener 
    *   The listener 
    * 
    * @see #setOnClearListener(OnClearListener, boolean) 
    */ 
    public void setOnClearListener(final OnClearListener clearListener) { 
     setOnClearListener(clearListener, false); 
    } 

    /** 
    * Disable the default functionality of the clear event - calling this won't allow for the input to be 
    * automatically 
    * cleared (it will give the ability to make custom implementations and react to the event before the clear). 
    */ 
    @SuppressWarnings("unused") 
    public void disableDefaultClearFunctionality() { 
     mDisableDefaultFunc = true; 
    } 

    /** 
    * Enable the default functionality of the clear event. Will automatically clear the input when the clear button is 
    * clicked. 
    */ 
    @SuppressWarnings("unused") 
    public void enableDefaultClearFunctionality() { 
     mDisableDefaultFunc = false; 
    } 

    /** 
    * Automatically show/hide the clear button based on the current input detected. 
    * <br/> 
    * If there is no input the clear button will be hidden. If there is input detected the clear button will be shown. 
    */ 
    public void updateClearButton() { 
     if (isEmpty()) { 
      hideClearButton(); 
     } else { 
      showClearButton(); 
     } 
    } 

    private boolean isEmpty() { 
     if (null == getText()) { 
      // Invalid editable text 
      return true; 
     } else if (TextUtils.isEmpty(getText().toString())) { 
      // Empty 
      return true; 
     } else if (TextUtils.isEmpty(getText().toString().trim())) { 
      // White spaces only 
      return true; 
     } 
     return false; 
    } 

    /** 
    * Hide the clear button. 
    * <br/> 
    * If an transition drawable was provided, it will be used to create an fade out effect, otherwise the default 
    * drawable resource will be used. 
    */ 
    public void hideClearButton() { 
     if (getCompoundDrawables()[2] == null) { 
      // The clear button was already hidden - do nothing 
      return; 
     } 

     if (null == mTransitionClearButtonHide) { 
      setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); 
      return; 
     } 

     mTransitionClearButtonHide.resetTransition(); 
     isTransitionInProgress.set(true); 

     mTransitionClearButtonHide.startTransition(TRANSITION_TIME); 
     setCompoundDrawablesWithIntrinsicBounds(null, null, mTransitionClearButtonHide, null); 

     transitionHandler.removeCallbacks(showClearButtonRunnable); 
     transitionHandler.removeCallbacks(hideClearButtonRunnable); 
     transitionHandler.postDelayed(hideClearButtonRunnable, TRANSITION_TIME); 
    } 

    /** 
    * Show the clear button. 
    * <br/> 
    * If an transition drawable was provided, it will be used to create an fade in effect, otherwise the default 
    * drawable resource will be used. 
    */ 
    public void showClearButton() { 
     if (getCompoundDrawables()[2] != null) { 
      // The clear button was already set - do nothing 
      return; 
     } 

     if (null == mTransitionClearButtonShow) { 
      setCompoundDrawablesWithIntrinsicBounds(0, 0, mImgClearButtonRes, 0); 
      return; 
     } 

     isTransitionInProgress.set(true); 

     mTransitionClearButtonShow.startTransition(TRANSITION_TIME); 
     setCompoundDrawablesWithIntrinsicBounds(null, null, mTransitionClearButtonShow, null); 

     transitionHandler.removeCallbacks(hideClearButtonRunnable); 
     transitionHandler.removeCallbacks(showClearButtonRunnable); 
     transitionHandler.postDelayed(showClearButtonRunnable, TRANSITION_TIME); 
    } 

    /** 
    * Custom contract which is used to notify any listeners that an clear event was triggered. 
    */ 
    public interface OnClearListener { 

     /** 
     * Clear event from the clear button triggered. 
     */ 
     void onClear(); 
    } 
} 

Когда я хочу, чтобы отобразить сообщение об ошибке, я использую следующую команду:

// Enable and show the error 
mClearView.requestFocus(); // we need to request focus, otherwise the error won't be shown 
mClearView.setError("Please choose an valid destination!", null); 

Если я использую: mClearView.setError("Please choose an valid destination!"), так что значок ошибки будет показано, кнопка ясно не будет показанный больше после этого.

+0

Разместите код пожалуйста. – earthw0rmjim

ответ

3

Поскольку документация setCompoundDrawablesWithIntrinsicBounds() (не так) четко сказано, что последующие вызовы должны перезаписывать ранее установленные вводимого коэффициента, а также документация setError() говорит следующее:

Устанавливает правую соединение вытяжке TextView к значку «ошибка» и задает сообщение об ошибке, которое будет отображаться во всплывающем окне , когда в TextView есть фокус.

Я предполагаю, что это ошибка.

Вызов setError(null) и настройками ранее установленный на null вводимых коэффициент перед установкой вашего нового Drawable возможного обходной путь:

void setError(String error) { 
    editText.setError(error); 
} 

void setCompoundDrawableRight(Drawable rightDrawable) { 
    editText.setError(null); 
    editText.setCompoundDrawables(null, null, null, null); 

    editText.setCompoundDrawablesWithIntrinsicBounds(null, null, rightDrawable, null); 
} 
Смежные вопросы