场合
我给自己写了一个自定义视图。它基本上是一个进度条,可以一次显示2个进度(例如视频的缓冲时间和播放时间)。我还希望用户与它进行交互(例如设置视频的时间)。但在这里我遇到了一个问题
问题
这种互动已经实施,理论上也很好。但在实际部分中,android对用户触摸和滑动的位置不够准确,无法正常工作。
红点表示我的手指在哪里。酒吧应该跟随手指的移动。但是你可以看到它并没有安静地到达现场。
问题
有没有办法在组件上接收用户手指的准确位置?
我的组件
有趣的东西发生在方法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);
}
}