2009-08-21 16 views
45

Estoy tratando de cargar un mapa de bits en Android que quiero mosaico. Actualmente estoy usando el siguiente en mi vista para mostrar un mapa de bits:Android Tile Bitmap

canvas.drawBitmap(bitmap, srcRect, destRect, null) 

que esencialmente quiero utilizar este mapa de bits de una imagen de fondo en mi aplicación como y me gustaría repetir el mapa de bits, tanto en la dirección X e Y. .

He visto la constante TileMode.REPEAT para la clase BitmapShader pero no estoy seguro de si esto se va a utilizar para repetir el mapa de bits real o si se usa para aplicar un filtro al mapa de bits.

+0

¿Alguien sabe cómo hacer esto en código java sin el uso de xml? – endryha

Respuesta

123

Lo haría en el xml en lugar del código java. No lo he intentado yo mismo pero encontré este ejemplo.

<xml version="1.0" encoding="utf-8"?> 
<LinearLayout 
android:id="@+id/MainLayout" 
xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="fill_parent" 
android:layout_height="fill_parent" 
android:orientation="vertical" 
android:background="@drawable/backrepeat" 
> 

entonces en un xml llamado backrepeat.xml

<bitmap xmlns:android="http://schemas.android.com/apk/res/android" 
    android:src="@drawable/back" 
    android:tileMode="repeat" /> 

reference

+2

solo para agregar, backrepeat.xml va en la carpeta "dibujable" –

+2

Esto no funcionaría para dibujar en un lienzo ... – stealthcopter

+0

Podría ser pedante aquí pero la primera línea debería leer - Neil

15

El backrepeat.xml anterior es con errores

<bitmap 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:src="@drawable/tile" 
    android:tileMode="repeat" 
    android:dither="true" /> 
+17

¿Por qué es defectuoso y cómo lo soluciona esto? –

+0

Este agrega: android: dither = "true", que no hace nada si el mosaico no funciona bien para empezar. –

34

cuenta de la versión del código:

BitmapDrawable TileMe = new BitmapDrawable(MyBitmap); 
    TileMe.setTileModeX(Shader.TileMode.REPEAT); 
    TileMe.setTileModeY(Shader.TileMode.REPEAT); 

    ImageView Item = new ImageView(this); 
    Item.setBackgroundDrawable(TileMe); 

Entonces, si usted tiene un dibujable al azulejo, esto se puede utilizar en lugar de hacer la BitmapDrawable:

BitmapDrawable TileMe = new BitmapDrawable(BitmapFactory.decodeResource(getResources(), R.drawable.tile)); 
+0

Eso funciona muy bien, pero ¿cómo lo repetirías solo verticalmente? Intenté eliminar el setTileModeX, pero ni siquiera funciona. –

+0

@WilliamL. Impar. Los [documentos] (http://developer.android.com/reference/android/graphics/drawable/BitmapDrawable.html#setTileModeX (android.graphics.Shader.TileMode)) parecen decir que debería funcionar solo con uno de ellos . Lo mejor es probar ['Shader.TileMode.CLAMP'] (http://developer.android.com/reference/android/graphics/Shader.TileMode.html) y ver qué sucede, entonces. – Izkata

+0

Funciona si lo repito horizontalmente solamente, pero no solo verticalmente. Y CLAMP hace lo mismo que no haber configurado el modo de mosaico en primer lugar. –

5

parece que algunas personas están interesadas en hacer esto en una vista, en el método de onDraw. El siguiente código ha trabajado para mí:

bgTile = BitmapFactory.decodeResource(context.getResources(), R.drawable.bg_tile); 

float left = 0, top = 0; 
float bgTileWidth = bgTile.getWidth(); 
float bgTileHeight = bgTile.getHeight(); 

while (left < screenWidth) { 
    while (top < screenHeight) { 
     canvas.drawBitmap(bgTile, left, top, null); 
     top += bgTileHeight; 
    } 
    left += bgTileWidth; 
    top = 0; 
} 
+0

Llena toda el área. El último mosaico puede no estar completo, el espacio de la derecha/parte inferior de la pantalla aún se dibujará. – kgiannakakis

+0

Solo estaba usando esto para un segmento de mi lienzo en lugar de todo, por lo que obviamente se obtiene un dibujo extra, entonces el ancho y la altura no son divisibles por el tamaño de imagen. Eliminé mi comentario ya que no es relevante para la pregunta. ¡Lo siento! – stealthcopter

+0

En este caso utilizaría BitmapDrawable.setBounds y BitmapDrawable.draw (Canvas) – tactoth

4
<xml version="1.0" encoding="utf-8"?> 
<LinearLayout 
    android:id="@+id/MainLayout" 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:orientation="vertical" 
    android:background="@drawable/back" 
    android:tileMode="repeat" 
> 

Esto funcionó bien para mí. No tuve que crear el mapa de bits por separado. Usé el atributo tileMode en el diseño.

+0

Gracias, me pareció que este es el enfoque más fácil. – patrickandroid

0

Si desea repetir el fondo solo verticalmente, puede establecer el ancho de su diseño en "wrap_content", mientras que si desea establecer el fondo para que se repita horizontalmente, establezca la altura en "wrap_content". Si tanto la altura como el ancho están configurados en "fill_parent", se colocarán en las direcciones X e Y.

Por ejemplo, el siguiente código se repetirá el fondo verticalmente:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="wrap_content" 
    android:layout_height="fill_parent" 
    android:background="@drawable/news_detail_activity_bg"> 
</LinearLayout> 
1

sólo hay que poner esta línea de códigos en el onCreate(): -

final Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.actionbar_bg); 
final BitmapDrawable bitmapDrawable = new BitmapDrawable(bmp); 
bitmapDrawable.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT); 
final ActionBar bar = getSupportActionBar(); 
bar.setBackgroundDrawable(bitmapDrawable); 
0
/* Tiled Layer Bitmap*/ 


public class TiledLayer { 
private int cellWidth; 
private int cellHeight; 
private int yPosition = 0, xPosition = 0; 
private int[][] grid; 
private Image image; 
private int[] tileXPositions; 
private int[] tileYPositions; 
private ArrayList animatedTiles; 
private int numberOfTiles; 
private int numberOfColumns; 
private int numberOfRows; 
private int gridColumns; 
private int gridRows, width, height; 

public TiledLayer(Image image, int columns, int rows, int tileWidth, 
     int tileHeight, int width, int height) { 
    this.grid = new int[columns][rows]; 
    this.gridColumns = columns; 
    this.gridRows = rows; 
    this.width = columns * tileWidth; 
    this.height = rows * tileHeight; 
    this.animatedTiles = new ArrayList(); 
    setStaticTileSet(image, tileWidth, tileHeight); 
    } 

public void setStaticTileSet(Image image, int tileWidth, int tileHeight) { 
    this.image = image; 
    this.cellWidth = tileWidth; 
    this.cellHeight = tileHeight; 
    int columns = 64;//image.getWidth()/tileWidth; 
    int rows =40;// image.getHeight()/tileHeight; 
    this.tileXPositions = new int[columns]; 
    int pos = 0; 
    for (int i = 0; i < columns; i++) { 
     this.tileXPositions[i] = pos; 
     pos += tileWidth; 
    } 
    this.tileYPositions = new int[rows]; 
    pos = 0; 
    for (int i = 0; i < rows; i++) { 
     this.tileYPositions[i] = pos; 
     pos += tileHeight; 
    } 

    if (columns * rows < this.numberOfTiles) { 
     // clear the grid, when there are not as many tiles as in the 
     // previous set: 
     for (int i = 0; i < this.grid.length; i++) { 
      for (int j = 0; j < this.grid[i].length; j++) { 
       this.grid[i][j] = 0; 
      } 
     } 
    } 
    this.numberOfTiles = columns * rows; 
    this.numberOfColumns = columns; 
    this.numberOfRows = rows; 
    } 

    public int createAnimatedTile(int staticTileIndex) { 
    if (staticTileIndex >= this.numberOfTiles) { 

     throw new IllegalArgumentException("invalid static tile index: " 
       + staticTileIndex + " (there are only [" 
       + this.numberOfTiles + "] tiles available."); 

    } 
    this.animatedTiles.add(new Integer(staticTileIndex)); 
    return -1 * (this.animatedTiles.size() - 1); 
} 

public void setAnimatedTile(int animatedTileIndex, int staticTileIndex) { 
    if (staticTileIndex >= this.numberOfTiles) { 

    } 
    int animatedIndex = (-1 * animatedTileIndex) - 1; 
    this.animatedTiles.set(animatedIndex, new Integer(staticTileIndex)); 
    } 

public int getAnimatedTile(int animatedTileIndex) { 
    int animatedIndex = (-1 * animatedTileIndex) - 1; 
    Integer animatedTile = (Integer) this.animatedTiles.get(animatedIndex); 
    return animatedTile.intValue(); 
} 
public void setCell(int col, int row, int tileIndex) { 
    if (tileIndex >= this.numberOfTiles) { 

     throw new IllegalArgumentException("invalid static tile index: " 
       + tileIndex + " (there are only [" + this.numberOfTiles 
       + "] tiles available."); 

    } 
    this.grid[col][row] = tileIndex; 
} 

public int getCell(int col, int row) { 
    return this.grid[col][row]; 
} 

public void fillCells(int col, int row, int numCols, int numRows, 
     int tileIndex) { 
    if (tileIndex >= this.numberOfTiles) { 

     throw new IllegalArgumentException("invalid static tile index: " 
       + tileIndex + " (there are only [" + this.numberOfTiles 
       + "] tiles available."); 

    } 
    int endCols = col + numCols; 
    int endRows = row + numRows; 
    for (int i = col; i < endCols; i++) { 
     for (int j = row; j < endRows; j++) { 
      this.grid[i][j] = tileIndex; 
     } 
    } 
} 

    public final int getCellWidth() { 
    return this.cellWidth; 
} 

    public final int getCellHeight() { 
    return this.cellHeight; 
} 

public final int getColumns() { 
    return this.gridColumns; 
} 

public final int getRows() { 
    return this.gridRows; 
} 

public final void paint(Graphics g) { 
    int clipX = 0;// g.getClipX(); 
    int clipY = 0;// g.getClipY(); 
    int clipWidth = width;// g.getClipWidth(); 
    int clipHeight = height;// g.getClipHeight(); 

    // jmt restore clip to previous state 

    int x = this.xPosition; 
    int y = this.yPosition; 
    int[][] gridTable = this.grid; 
    for (int i = 0; i < this.gridColumns; i++) { 
     int[] gridRow = gridTable[i]; 
     for (int j = 0; j < gridRow.length; j++) { 
      int cellIndex = gridRow[j]; 
      if (cellIndex != 0) { 
       // okay this cell needs to be rendered: 
       int tileIndex; 
       if (cellIndex < 0) { 
        Integer tile = (Integer) this.animatedTiles 
          .get((-1 * cellIndex) - 1); 
        tileIndex = tile.intValue() - 1; 
       } else { 
        tileIndex = cellIndex - 1; 
       } 
       // now draw the tile: 
       g.save(Canvas.CLIP_SAVE_FLAG); 
       // jmt: clear the screen 
       Rect r = new Rect(0, 0, cellWidth, cellHeight); 
       g.clipRect(r); 
       g.setClip(x, y, this.cellWidth, this.cellHeight); 
       int column = tileIndex % this.numberOfColumns; 
       int row = tileIndex/this.numberOfColumns; 
       int tileX = x - this.tileXPositions[column]; 
       int tileY = y - this.tileYPositions[row]; 

       g.drawImage(this.image, tileX, tileY); 
       g.restore(); 
      } 
      y += this.cellHeight; 
     } // for each row 
     y = this.yPosition; 
     x += this.cellWidth; 
    } // for each column 

    // reset original clip: 
    g.setClip(clipX, clipY, clipWidth, clipHeight); 
} 

}