我也有類似的問題,絕不是真正的表現感到滿意。這一切都是當我將我的比賽場地擴大到30 * 30時,我獲得了900個ImageViews。我嘗試了很多優化,但是性能和內存在設備上很高且不可預測。
所以我做的是創建一個自定義視圖。只有一個。這個視圖然後在畫布上繪製正方形。我很驚訝,現在我可以成千上萬的正方形(100x100),並且性能非常流暢。
我在這裏發佈我的觀點的骨架與所有廢話刪除的靈感,我強烈建議你按照這種方法。
/**
* ChequeredView is a view that displays a 2D square matrix, where each square can be individually selected.
* For high performance, It only uses one view regardless of the matrix size (everything is drawn in a canvas)
* @author rodo 13 march 2014 <[email protected]>
*/
public class ChequeredView extends View {
private final String TAG="ChequeredView";
private static final int
DEFAULT_MATRIX_SIZE_COLS=20,
DEFAULT_MATRIX_SIZE_COLS=20,
DEFAULT_SQUARE_SIZE=100;
private int mCols=DEFAULT_MATRIX_SIZE_COLS,
mRows=DEFAULT_MATRIX_SIZE_ROWS;
/* Save touch press */
private int mTouchX=0, mTouchY=0;
///////////////// VIEW CODE
public ChequeredView(Context context, AttributeSet attrs) { super(context, attrs); }
public ChequeredView(Context context) { super(context); }
/**
* Report a size of your view that is: SquareSize * NUM_COLS x SquareSize * NUM_ROWS. You will paint it later.
*/
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// calculate optimum square size
mStyleSquareSize=MeasureSpec.getSize(widthMeasureSpec)/mSquaresPerCanvas;
// report total size
setMeasuredDimension(DEFAULT_MATRIX_SIZE_COLS * mStyleSquareSize, DEFAULT_MATRIX_SIZE_ROWS * mStyleSquareSize);
}
@Override
public void onDraw(Canvas canvas) {
render(canvas);
}
@Override
public boolean onTouchEvent(android.view.MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// I execute the action in ACTION_UP so I can put this inside a scrollview and touch doesn't interferre the scroll.
mTouchX=(int) event.getX();
mTouchY=(int) event.getY();
return true;
case MotionEvent.ACTION_UP:
// only process touch if finger has not moved very much (if it has, it's a fling on parent)
if (isApprox(event.getX(), mTouchX, 5) && (isApprox(event.getY(), mTouchY, 5)))
processTouch((int)event.getX(), (int)event.getY());
break;
}
return false;
};
/**
* Check if a value is close to another one
* @param value Value to check
* @param ref Reference value
* @param threshold Threshold
* @return true if |val-ref|<threshold
*/
private boolean isApprox(float value, int ref, int threshold) {
float result=Math.abs(value-ref);
return (result<threshold);
}
///////////////// VIEW METHODS
public void setMatrixSize(int numx, int numy) {
mRows=numx;
mCols=numy;
invalidate();
}
///////////////// VIEW INTERNALS
/**
* Renders the whole squaremap
* @param canvas
*/
private void render(Canvas canvas) {
if (canvas==null) return;
for (int x=0; x<mCols; x++) {
for (int y=0; y<mRows; y++) {
render_square(canvas, x, y);
}
}
}
/**
* Renders one of the squares
* @param canvas Canvas where to draw
* @param nCol The column
* @param nRow The row
*/
private void render_square(Canvas canvas, int nCol, int nRow) {
String text=null, transition=null;
int delay=0;
Paint paint=null;
int cx=nCol*mStyleSquareSize, cy=nRow*mStyleSquareSize;
canvas.save();
canvas.translate(cx, cy);
canvas.drawRect(mStyleSquareMargin, mStyleSquareMargin, mStyleSquareSize-2*mStyleSquareMargin, mStyleSquareSize-2*mStyleSquareMargin, paint);
// this draws an square (I use vectorial squares with text rather than images, but just change drawRect to drawBitmap)
// just change it for drawBitmap() to draw one bitmap
canvas.restore();
}
/**
* Process a touch on the map area
* @param x raw x coordinate
* @param y raw y coordinate
*/
private void processTouch(int x, int y) {
int nx=x/mStyleSquareSize, ny=y/mStyleSquareSize;
mSelectedX=nx;
mSelectedY=ny;
if (mSquareListener!=null) {
mSquareListener.onSquareSelected(nx, ny, data);
}
invalidate();
}
}
如果我理解你在正確的方式比賽的想法,與imageviews網格是靜態 - 這意味着圖像視圖的數量總是相同的,對嗎?爲什麼不更新imageView背景或圖像而不是重新創建它們?在我看來,游泳池的想法並不好 - 如果你需要實現某種方式滾動的列表或網格視圖,可能會有用 – MP23
對不起,我還沒有提到它,但我正在移動ImageViews周圍(使用Tween引擎進行動畫處理),因此它們在每一輪中都沒有相同的位置。否則,我完全同意你的觀點,只有改變圖像源纔是明智之舉。此外,我還有更多ImageView用於動畫化兩張牌的合併。希望對你有意義。 –
好的,那麼我建議使用某種集合,例如列表,每一個沒有更多必要的圖像視圖應該去那裏,如果需要一些新的ImageView,那麼你應該首先檢查你的列表是否不包含一個,並更新其背景和位置。當然,如果你使用它,你應該從列表中刪除它。僅當列表爲空時才創建新的ImageView。我認爲它是簡單的緩存機制之一,但它在例如ListView中正常工作(重用行視圖) –
MP23