Ответ 1
Я думаю, что окончательный ответ здесь - реализовать свой собственный класс, расширив SurfaceView
, а затем переопределив onDraw
(холст холста)
Затем вы можете использовать подпрограммы Canvas для визуализации вашего контроля.
Есть много хороших примеров, если вы google.
Для начала инициализируйте представление поверхности:
// So things actually render
setDrawingCacheEnabled(true);
setWillNotDraw(false);
setZOrderOnTop(true);
// Controls the drawing thread.
getHolder().addCallback(new CallbackSurfaceView());
Переопределите onDraw и добавьте процедуры рендеринга. Вы можете сложить их как вы идете.
public void onDraw(Canvas canvas) {
// Always Draw
super.onDraw(canvas);
drawBackground(canvas);
drawKnobIndentWell(canvas);
drawKnob(canvas);
drawKnobLED( canvas ); //etc....
}
Пример обратного вызова и поток обновлений:
/**
* This is the drawing callback.
* It handles the creation and destruction of the drawing thread when the
* surface for drawing is created and destroyed.
*/
class CallbackSurfaceView implements SurfaceHolder.Callback {
Thread threadIndeterminant;
RunnableProgressUpdater runnableUpdater;
boolean done = false;
/**
* Kills the running thread.
*/
public void done() {
done = true;
if (null != runnableUpdater) {
runnableUpdater.done();
}
}
/**
* Causes the UI to render once.
*/
public void needRedraw() {
if (runnableUpdater != null) {
runnableUpdater.needRedraw();
}
}
/**
* When the surface is created start the drawing thread.
* @param holder
*/
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (!done) {
threadIndeterminant = new Thread(runnableUpdater = new RunnableProgressUpdater());
threadIndeterminant.start();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
/**
* When the surface is destroyed stop the drawing thread.
* @param holder
*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (null != runnableUpdater) {
runnableUpdater.done();
threadIndeterminant = null;
runnableUpdater = null;
}
}
}
/**
* This is the runnable for the drawing operations. It is started and stopped by the callback class.
*/
class RunnableProgressUpdater implements Runnable {
boolean surfaceExists = true;
boolean needRedraw = false;
public void done() {
surfaceExists = false;
}
public void needRedraw() {
needRedraw = true;
}
@Override
public void run() {
canvasDrawAndPost();
while (surfaceExists) {
// Renders continuously during a download operation.
// Otherwise only renders when requested.
// Necessary so that progress bar and cirlce activity update.
if (syncContext.isRunning()) {
canvasDrawAndPost();
needRedraw = true;
} else if (needRedraw) {
canvasDrawAndPost();
needRedraw = false;
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// Don't care
}
}
// One final update
canvasDrawAndPost();
}
/**
* Routine the redraws the controls on each loop.
*/
private synchronized void canvasDrawAndPost() {
Canvas canvas = getHolder().lockCanvas();
if (canvas != null) {
try {
draw(canvas);
} finally {
getHolder().unlockCanvasAndPost(canvas);
}
}
}
}
Если вы решите пойти по этому маршруту, вы можете настроить свой контроль из XML, используя пользовательские значения.
<com.killerknob.graphics.MultimeterVolumeControl
android:id="@+id/volume_control"
android:layout_below="@id/divider_one"
android:background="@android:color/white"
android:layout_width="match_parent"
android:layout_height="60dp"
android:minHeight="60dp"
custom:ledShadow="#357BBB"
custom:ledColor="#357BBB"
custom:knobBackground="@color/gray_level_13"
custom:knobColor="@android:color/black"
/>
При создании настраиваемого элемента управления вы ссылаетесь на него по имени своего пакета. Вы создаете пользовательскую переменную в файле ресурсов под знаками /, а затем ссылаетесь их в вашем классе.
Подробнее здесь:
http://developer.android.com/training/custom-views/create-view.html
Это может быть больше работы, чем вы хотите сделать, но я думаю, что вы получите более профессионально выглядящий контроль, а анимация будет более плавной.
Во всяком случае, выглядит забавный проект. Удачи.