在自定义视图中重复执行任务并延迟时间

时间:2017-06-12 11:05:48

标签: android android-custom-view android-handler

问题Repeat a task with a time delay?讨论活动中的重复任务。最高投票的答案看起来很适合这种情况。我试图在完全自定义的EditText中制作一个闪烁的光标。我尝试复制和调整Android TextViewEditor代码中的代码,但我没有得到任何眨眼的内容。

以下是我一直试图开始工作的一些当前代码:

private boolean shouldBlink() {
    if (!mCursorVisible || !isFocused()) return false;

    final int start = getSelectionStart();
    if (start < 0) return false;

    final int end = getSelectionEnd();
    if (end < 0) return false;

    return start == end;
}

void makeBlink() {
    if (shouldBlink()) {
        mShowCursor = SystemClock.uptimeMillis();
        if (mBlink == null) mBlink = new Blink();
        this.removeCallbacks(mBlink);
        this.postDelayed(mBlink, BLINK);
    } else {
        if (mBlink != null) this.removeCallbacks(mBlink);
    }
}

private class Blink implements Runnable {
    private boolean mCancelled;

    public void run() {
        if (mCancelled) {
            return;
        }

        MongolEditText.this.removeCallbacks(this);

        if (shouldBlink()) {
            if (mLayout != null) {
                MongolEditText.this.invalidateCursorPath();
            }

            MongolEditText.this.postDelayed(this, BLINK);
        }
    }

    void cancel() {
        if (!mCancelled) {
            MongolEditText.this.removeCallbacks(this);
            mCancelled = true;
        }
    }

    void uncancel() {
        mCancelled = false;
    }
}

private void invalidateCursorPath() {
    int start = getSelectionStart();
    if (start < 0) return;
    Rect cursorPath = getCursorPath(start);
    invalidate(cursorPath.left, cursorPath.top, cursorPath.right, cursorPath.bottom);
}

private void suspendBlink() {
    if (mBlink != null) {
        mBlink.cancel();
    }
}

private void resumeBlink() {
    if (mBlink != null) {
        mBlink.uncancel();
        makeBlink();
    }
}

@Override
public void onScreenStateChanged(int screenState) {
    switch (screenState) {
        case View.SCREEN_STATE_ON:
            resumeBlink();
            break;
        case View.SCREEN_STATE_OFF:
            suspendBlink();
            break;
    }
}

@Override
public void onAttachedToWindow() {
    super.onAttachedToWindow();
    resumeBlink();
}

@Override
public void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    suspendBlink();
}

我决定用一个更简单的例子退一步解决问题,所以我创建了一个MCVE。我的答案(假设我可以做到)如下。我的目标如下:

  • 视图在点击时开始重复任务。
  • 视图被销毁时,应取消处理程序的可运行代码。

我的基本问题是如何让视图开始自己的重复任务,改变它的外观? (就像眨眼一样)

1 个答案:

答案 0 :(得分:2)

以下示例说明如何在自定义视图上设置重复任务。该任务通过使用每秒运行一些代码的处理程序来工作。触摸视图会启动和停止任务。

public class MyCustomView extends View {

    private static final int DELAY = 1000; // 1 second
    private Handler mHandler;

    // keep track of the current color and whether the task is running
    private boolean isBlue = true;
    private boolean isRunning = false;

    // constructors
    public MyCustomView(Context context) {
        this(context, null, 0);
    }
    public MyCustomView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public MyCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mHandler = new Handler();
    }

    // start or stop the blinking when the view is touched
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        if (event.getAction() == MotionEvent.ACTION_UP) {
            if (isRunning) {
                stopRepeatingTask();
            } else {
                startRepeatingTask();
            }
            isRunning = !isRunning;
        }
        return true;
    }

    // alternate the view's background color
    Runnable mRunnableCode = new Runnable() {
        @Override
        public void run() {
            if (isBlue) {
                MyCustomView.this.setBackgroundColor(Color.RED);
            }else {
                MyCustomView.this.setBackgroundColor(Color.BLUE);
            }
            isBlue = !isBlue;

            // repost the code to run again after a delay
            mHandler.postDelayed(mRunnableCode, DELAY);
        }
    };

    // start the task
    void startRepeatingTask() {
        mRunnableCode.run();
    }

    // stop running the task, cancel any current code that is waiting to run
    void stopRepeatingTask() {
        mHandler.removeCallbacks(mRunnableCode);
    }

    // make sure that the handler cancels any tasks left when the view is destroyed 
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        stopRepeatingTask();
    }
}

以下是点击后的视图。

enter image description here

感谢this answer提出想法。