0

Situation
I wrote my self a custom view. It basically is a progress bar which can display 2 progresses at once (for instance buffered time and played time of a video). I also want the user to interact with it (for instance setting the time of a video). But here i run into a problem

Problem
The interaction is already implemented and works fine in theory. But in the practical part android is not accurate enough about the location of the users touch and slide to properly work.

The red spot indicates where i had my finger.The bar is supposed to follow the movement of the finger. But as you can see it doesn't quiet hit the spot.

enter image description here
enter image description here

Question
Is there some way to receive an accurate location of the users finger on a component?

My Component
The interesting stuff happens inside the method initListener()

public final class ProgressBarView extends View {

  /* Values */
  private double progressBackground = 0;
  private double progressForeground = 0;
  private boolean inputEnabled = true;
  private boolean paused;
  private final List<ProgressChangeListener> listenerPool = new ArrayList<>();

  /* UI */
  private final Paint colorOutlineBar = new Paint();
  private final Paint colorBackgroundBar = new Paint();
  private final Paint colorBackgroundProgress = new Paint();
  private final Paint colorForegroundProgress = new Paint();

  private final Paint colorOutlineIndicator = new Paint();
  private final Paint colorBackgroundIndicator = new Paint();

  private final int barRounding;
  private final int barOutlineThickness;
  private final int indicatorRadius;
  private final int indicatorOutlineThickness;

  public ProgressBarView(Context pContext, AttributeSet pAttributes) {
    super(pContext, pAttributes);
    colorOutlineBar.setColor(getColor(pAttributes, R.styleable.ProgressBarView_colorOutlineBar, R.color.black));
    colorBackgroundBar.setColor(getColor(pAttributes, R.styleable.ProgressBarView_colorBackgroundBar, R.color.dark_grey));
    colorBackgroundProgress.setColor(getColor(pAttributes, R.styleable.ProgressBarView_colorBackgroundProgress, R.color.light_gray));
    colorForegroundProgress.setColor(getColor(pAttributes, R.styleable.ProgressBarView_colorForegroundProgress, R.color.white));
    colorOutlineIndicator.setColor(getColor(pAttributes, R.styleable.ProgressBarView_colorOutlineIndicator, R.color.black));
    colorBackgroundIndicator.setColor(getColor(pAttributes, R.styleable.ProgressBarView_colorBackgroundIndicator, R.color.white));

    barRounding = getIntegerValue(pAttributes, R.styleable.ProgressBarView_barRounding, 10);
    barOutlineThickness = getIntegerValue(pAttributes, R.styleable.ProgressBarView_barOutlineThickness, 4);
    indicatorRadius = getIntegerValue(pAttributes, R.styleable.ProgressBarView_indicatorRadius, 10);
    indicatorOutlineThickness = getIntegerValue(pAttributes, R.styleable.ProgressBarView_indicatorOutlineThickness, 4);

    initListener();
  }

  public interface ProgressChangeListener {

    public void onPause(ProgressBarView pView);

    public void onResume(ProgressBarView pView);

  }

  public final List<ProgressChangeListener> getListenerPool() {
    return listenerPool;
  }

 /* *JUST A BUNCH OF GETTERS AND SETTERS FOR THE FIELDS ABOVE* */

@Override
  protected final void onDraw(final Canvas pCanvas) {
    final RectF barOutline = new RectF(indicatorRadius, 0, getWidth() - indicatorRadius, getHeight());
    final RectF barBackground = new RectF(indicatorRadius + barOutlineThickness, barOutlineThickness, getWidth() - indicatorRadius - barOutlineThickness, getHeight() - barOutlineThickness);
    final RectF barProgressBackground = new RectF(indicatorRadius + barOutlineThickness, barOutlineThickness, getPositionForProgress(progressBackground), getHeight() - barOutlineThickness);
    final RectF barProgressForeground = new RectF(indicatorRadius + barOutlineThickness, barOutlineThickness, getPositionForProgress(progressForeground), getHeight() - barOutlineThickness);

    pCanvas.drawRoundRect(barOutline, barRounding, barRounding, colorOutlineBar);
    pCanvas.drawRoundRect(barBackground, barRounding, barRounding, colorBackgroundBar);
    pCanvas.drawRoundRect(barProgressBackground, barRounding, barRounding, colorBackgroundProgress);
    pCanvas.drawRoundRect(barProgressForeground, barRounding, barRounding, colorForegroundProgress);

    final int x = getPositionForProgress(progressForeground);
    final int y = getHeight() / 2;
    pCanvas.drawCircle(x, y, indicatorRadius, colorOutlineIndicator);
    pCanvas.drawCircle(x, y, indicatorRadius - indicatorOutlineThickness, colorBackgroundIndicator);


    invalidate();
  }

  private void initListener() {
    setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            if (inputEnabled) {
                switch (motionEvent.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        postAsyncPause();
                        return true;
                    case MotionEvent.ACTION_UP: {
                        float x = motionEvent.getX() * motionEvent.getXPrecision();
                        progressForeground = x / (getWidth() - indicatorRadius * 2) * 100;
                        postAsyncResume();
                        return true;
                    }
                    case MotionEvent.ACTION_MOVE: {
                        float x = motionEvent.getX() * motionEvent.getXPrecision();
                        progressForeground = x / (getWidth() - indicatorRadius * 2) * 100;
                        return true;
                    }
                    default:
                        break;
                }
            }
            return false;
        }
    });
  }

  private final void postAsyncPause() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            for (ProgressChangeListener listener : listenerPool) {
                listener.onPause(ProgressBarView.this);
            }
        }
    }).start();
  }

  private final void postAsyncResume() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            for (ProgressChangeListener listener : listenerPool) {
                listener.onResume(ProgressBarView.this);
            }
        }
    }).start();
  }

  private final int getColor(final AttributeSet pAttributes, final int pAttributeId, final int pColorId) {
    final TypedArray a = getContext().obtainStyledAttributes(pAttributes, R.styleable.ProgressBarView);
    int color = a.getColor(pAttributeId, -1);
    a.recycle();
    if (color == -1) {
        color = getResources().getColor(pColorId);
    }
    return color;
  }

  private final int getIntegerValue(AttributeSet pAttributes, int pAttributeId, int pDefaultValue) {
    final TypedArray a = getContext().obtainStyledAttributes(pAttributes, R.styleable.ProgressBarView);
    int color = a.getInteger(pAttributeId, -1);
    a.recycle();
    if (color == -1) {
        return pDefaultValue;
    }
    return color;
    }


  private final int getPositionForProgress(double pPercentage) {
    int barWidth = getWidth() - barOutlineThickness - 2 * indicatorRadius;
    if (pPercentage >= 100) {
        return barWidth;
    } else if (pPercentage <= 0) {
        return indicatorRadius;
    }
    return (int) (barWidth / 100 * pPercentage);
  }

}
Basti
  • 1,117
  • 12
  • 32

0 Answers0