我需要加载汽车的不同图像,这些图像基本保存在drawable中以模拟360度旋转,当用户拖动视图时,我设置了拖动距离,一旦用户越过它我将加载下一帧。我正在使用表面视图并在画布上绘制图像。由于图像太大,我无法一次将所有图像加载到内存中,所以我通过仅将当前图像保存在内存中来动态加载图像。但这种做法太迟钝了。谁能指出我做错了什么?或任何其他更好的方法来实现同样的目标。谢谢你的帮助。
这是我的代码
/ ** * @author rajeshcp *作为视图中顶视图的类 * CarDetailsActivity的层次结构 * @since 2013年2月13日 * /
public class VirtualView extends SurfaceView implements SurfaceHolder.Callback, OnTouchListener, TweenListener {
private final int frame_width = 1024;
private final int frame_height = 462;
private InteractionListener mInteractionListener;
private final int mSnapVelocity = 1000;
private VelocityTracker mVelocityTracker;
protected int mTouchSlop;
private int mMaxVelocity;
private Rect mViewArea;
private IQTweener mValueanimator;
private ColorVariationVO mColorVariationVO;
/**************Indicates the current frame*********************/
private int mCurrentFrameIndex;
/**********Initial touch x coordinate**************/
private int mInitialTouchX;
/***********The drag distance for frame change***********/
private int mDragInterWell = 10;
private final int mTotalFrames = 36;
protected final int mMaxFrameSkip = 3;
/**************Identity matrix**********************/
private Matrix mIdentityMatrix;
private Paint mPaint;
/*********The bitmap to be drawn over the canvas*********/
private Bitmap mCurrentFrame;
private ViewUpdater mViewUpdater;
/*++++++++++++++++++++++++++++++++++++++++++++++*/
/*+++++++++++++Getters and Setters++++++++++++++*/
/*++++++++++++++++++++++++++++++++++++++++++++++*/
/**
* @param of type null
* @return mColorVariationVO of type ColorVariationVO
* getter function for mColorVariationVO
* @since Feb 13, 2013
* @author rajeshcp
*/
public ColorVariationVO getmColorVariationVO() {
return mColorVariationVO;
}
/**
* @param mColorVariationVO of type ColorVariationVO
* @return of type null
* setter function for mColorVariationVO
* @since Feb 13, 2013
* @author rajeshcp
*/
public void setmColorVariationVO(ColorVariationVO mColorVariationVO) {
this.mColorVariationVO = mColorVariationVO;
loadNextFrame();
}
/**
* @param context of type Context
* @return of type VirtualView
* Constructor function
* @since Feb 13, 2013
* @author rajeshcp
*/
public VirtualView(Context context) {
super(context);
init();
}
/**
* @param context of type Context
* @param attrs of type AttributeSet
* @return of type VirtualView
* Constructor function
* @since Feb 13, 2013
* @author rajeshcp
*/
public VirtualView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
/**
* @param context of type Context
* @param attrs of type AttributeSet
* @param defStyle of type int
* @return of type VirtualView
* Constructor function
* @since Feb 13, 2013
* @author rajeshcp
*/
public VirtualView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
/**
* @param of type null
* @return of type null
* function which will initialize the values for the view
* @since 13 Feb 2013
*/
private void init()
{
setZOrderOnTop(true);
getHolder().setFormat(PixelFormat.TRANSPARENT);
mPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG | Paint.ANTI_ALIAS_FLAG);
mIdentityMatrix = new Matrix();
mCurrentFrameIndex = 0;
mViewUpdater = new ViewUpdater();
mInteractionListener = new InteractionListener();
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
mTouchSlop = configuration.getScaledTouchSlop();
mMaxVelocity = configuration.getScaledMaximumFlingVelocity();
getHolder().addCallback(this);
setOnTouchListener(this);
setLayerType(View.LAYER_TYPE_HARDWARE, mPaint);
}
/**
* @param direction of type int
* @return of type null
* function which will change the current frame index
* @since Feb 13, 2013
* @author rajeshcp
*/
private void initiateFrameChange(final int direction)
{
mCurrentFrameIndex += Math.max(-mMaxFrameSkip, Math.min(mMaxFrameSkip, direction));
if( mCurrentFrameIndex > (mTotalFrames - 1) )
{
mCurrentFrameIndex = (mCurrentFrameIndex % ( mTotalFrames - 1) );
}else if( mCurrentFrameIndex < 0 )
{
mCurrentFrameIndex = (mTotalFrames - 1) + (mCurrentFrameIndex % (mTotalFrames - 1));
}
loadNextFrame();
}
/**
* @param index of type int
* @return of type Bitmap
* function which will create the bitmap form the
* resources
* @since Feb 13, 2013
* @author rajeshcp
*/
@SuppressLint("UseSparseArrays")
private Bitmap getFrame(final int index)
{
Bitmap bitmap = null;
if( mColorVariationVO != null)
{
final int drawableId = getResourceId(index);
try
{
bitmap = BitmapFactory.decodeResource(getResources(), drawableId);
}catch (Exception e) {
Log.d(getClass().getName(), e.getLocalizedMessage());
}
}
return bitmap;
}
/**
* @param index of type int
* @return of type int
* function which create the resource id
* from index
* @since Feb 18, 2013
* @author rajeshcp
*/
private int getResourceId(final int index)
{
final String frameName = mColorVariationVO.getmCarAssetPath() + "_" + index;
int drawableId = 0;
try {
@SuppressWarnings("rawtypes")
Class res = R.drawable.class;
Field field = res.getField(frameName);
drawableId = field.getInt(null);
}
catch (Exception e) {
Log.e(getClass().getName(), "Failure to get drawable id.", e);
}
return drawableId;
}
/* (non-Javadoc)
* @see android.view.View#onDraw(android.graphics.Canvas)
* @since Feb 13, 2013
* @author rajeshcp
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if( mCurrentFrame != null && canvas != null )
{
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
mIdentityMatrix.reset();
// mPaint.setStyle(Paint.Style.STROKE);
// mPaint.setStrokeWidth(1);
// mPaint.setColor(Color.MAGENTA);
// mPaint.setTextSize(100);
//
// canvas.drawText(String.valueOf(mCurrentFrameIndex), (getWidth() / (mTotalFrames - 1) ) * mCurrentFrameIndex, (getHeight() - 100) / 2, mPaint);
mIdentityMatrix.postTranslate(getWidth() - frame_width, (getHeight() - frame_height) / 2);
canvas.drawBitmap(mCurrentFrame, mIdentityMatrix, mPaint);
}
}
/* (non-Javadoc)
* @see android.view.SurfaceHolder.Callback#surfaceChanged(android.view.SurfaceHolder, int, int, int)
* @since Feb 13, 2013
* @author rajeshcp
*/
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
/* (non-Javadoc)
* @see android.view.SurfaceHolder.Callback#surfaceCreated(android.view.SurfaceHolder)
* @since Feb 13, 2013
* @author rajeshcp
*/
@Override
public void surfaceCreated(SurfaceHolder holder) {
if( mViewArea == null )
{
int top = (getHeight() - frame_height) / 2;
int left = getWidth() - frame_width;
mViewArea = new Rect(left, top, frame_width + left, frame_height + top);
}
mDragInterWell = (int)(mViewArea.width() / (2 * mTotalFrames));
if( mViewUpdater == null)
{
init();
}
mViewUpdater.start();
mInteractionListener.start();
}
/* (non-Javadoc)
* @see android.view.SurfaceHolder.Callback#surfaceDestroyed(android.view.SurfaceHolder)
* @since Feb 13, 2013
* @author rajeshcp
*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if(mViewUpdater != null)
{
mViewUpdater.setRun(false);
mViewUpdater = null;
mInteractionListener.mIsRunning = false;
mInteractionListener = null;
}
}
private boolean isScrolled = false;
/* (non-Javadoc)
* @see android.view.View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent)
* @since Feb 13, 2013
* @author rajeshcp
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
mInteractionListener.queueEvent(event);
return true;
}
/**
* @param velocity of type int
* @return of type null
* function which will initiate the
* fling animation
* @since Feb 15, 2013
* @author rajeshcp
*/
private void initiateFling(int velocity)
{
return;
// int maxDuration = mMaxFrameSkip * mSnapVelocity;
// velocity = Math.max(-maxDuration, Math.min(maxDuration, velocity));
// int end = ((int)( velocity / mSnapVelocity )) * mTotalFrames;
//
// if( mValueanimator == null )
// {
// mValueanimator = new IQTweener(mCurrentFrameIndex, mTotalFrames - 1);
// mValueanimator.setmListener(this);
// }
// mValueanimator.setMduration(2000);
// mValueanimator.setmStart(mCurrentFrameIndex);
// mValueanimator.setmEnd(end);
// mValueanimator.start();
}
/**
* @param of type null
* @return of type null
* function which will clear
* the touch values
* @since Feb 15, 2013
* @author rajeshcp
*/
private void onTouchEnd()
{
isScrolled = false;
mVelocityTracker.clear();
mVelocityTracker.recycle();
mVelocityTracker = null;
mInitialTouchX = 0;
}
/* (non-Javadoc)
* @see com.inkoniq.iqpromomultitouch.animations.IQTweener.TweenListener#onUpdate(java.lang.Object)
* @since Feb 15, 2013
* @author rajeshcp
*/
@Override
public void onUpdate(float mCurrent) {
final int mIndex = (int) mCurrent;
if( mIndex > (mTotalFrames - 1) )
{
mCurrentFrameIndex = (mIndex % ( mTotalFrames - 1) );
}else if( mIndex < 0 )
{
mCurrentFrameIndex = (mTotalFrames - 1) + (mIndex % (mTotalFrames - 1));
}
}
/**
* @param of type null
* @return of type null
* function which will load the next frame from local storage
* @since Feb 13, 2013
* @author rajeshcp
*/
private void loadNextFrame()
{
final Bitmap frame = getFrame(mCurrentFrameIndex);
if(mCurrentFrame != null)
{
Bitmap temp = mCurrentFrame;
mCurrentFrame = frame;
temp.recycle();
temp = null;
}else
{
mCurrentFrame = frame;
}
}
/**
* @author rajeshcp
* class which will take care of updating the view
* @since 13 Feb 2013
*/
private class ViewUpdater extends Thread
{
private SurfaceHolder surface;
private boolean run = true;
/**
* @param run of type boolean
* @return of type null
* setter function for run
* @since 13 Feb 2013
*/
public void setRun(boolean run) {
this.run = run;
}
/**
* @param surface of type SurfaceHolder
* @param gameView of type GameView
* Constructor function
* @since 13 Feb 2013
*/
public ViewUpdater()
{
}
/*
* (non-Javadoc)
* @see java.lang.Thread#run()
* @since Feb 13, 2013
* @author rajeshcp
*/
@Override
public void run() {
Canvas canvas;
while (run) {
canvas = null;
try {
surface = getHolder();
canvas = surface.lockCanvas(null);
synchronized (surface) {
onDraw(canvas);
}
} finally {
if (canvas != null) {
surface.unlockCanvasAndPost(canvas);
}
}
}
}
}
/**
* @author rajeshcp
* Class which will handle the touch
* events
* @since 19 Feb 2013
*/
private class InteractionListener extends Thread
{
ArrayList<MotionEvent> mEventQueue;
boolean mIsRunning = false;
/**
* @param of type null
* @return of type InteractionListener
* Constructor function
* @since Feb 19, 2013
* @author rajeshcp
*/
public InteractionListener()
{
init();
}
/**
* @param of type null
* @return of type null
* @since Feb 19, 2013
* @author rajeshcp
*/
private void init()
{
mIsRunning = true;
mEventQueue = new ArrayList<MotionEvent>();
}
/**
* @param event of type MotionEvent
* @return of type null
* function which will add the event to
* the mEventQueue
* @since Feb 19, 2013
* @author rajeshcp
*/
private void queueEvent(MotionEvent event)
{
mEventQueue.add(event);
}
/**
* @param event of type MotionEvent
* @return of type null
* function which will process the touch event
* @since Feb 19, 2013
* @author rajeshcp
*/
private void onTouch(MotionEvent event) {
if( event == null )
return;
if( mVelocityTracker == null )
{
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
if( !mViewArea.contains((int)event.getX(), (int)event.getY()) )
{
return;
}
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN :
{
if( mValueanimator != null )
{
mValueanimator.cancel();
}
isScrolled = false;
mInitialTouchX = (int)event.getX();
break;
}
case MotionEvent.ACTION_MOVE :
{
final int currentX = (int)event.getX();
final int draggedDistance = (currentX - mInitialTouchX);
if( draggedDistance != 0 && draggedDistance % mDragInterWell == 0 )
{
isScrolled = true;
initiateFrameChange(draggedDistance / mDragInterWell);
Log.d(getClass().getName(), "frameIndex = " + mCurrentFrameIndex);
mInitialTouchX = currentX;
}
break;
}
case MotionEvent.ACTION_UP :
{
if( isScrolled )
{
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaxVelocity);
int velocityX = (int) velocityTracker.getXVelocity();
if( (velocityX > mSnapVelocity) || (velocityX < -mSnapVelocity) )
{
initiateFling(velocityX);
}
}
onTouchEnd();
break;
}
case MotionEvent.ACTION_CANCEL :
{
onTouchEnd();
break;
}
default :
{
break;
}
}
}
/* (non-Javadoc)
* @see java.lang.Thread#run()
* @since Feb 19, 2013
* @author rajeshcp
*/
@Override
public void run() {
while ( mIsRunning ) {
while ( mEventQueue.size() > 0 ) {
onTouch(mEventQueue.remove(0));
try
{
Thread.sleep(16);
}catch (Exception e) {
}
}
}
}
}
}
答案 0 :(得分:1)
由于尝试显示模拟的360度视图的复杂性,您可能需要考虑使用OpenGL来处理此渲染。这将为您提供更多关于内容显示方式的能力,并将简化您的实施。
然而;这并不是说这是一个简单的实现。但这将是实现此类目标的最佳方式。