2009-08-21 2 views
45

Я пытаюсь загрузить растровое изображение в Android, которое я хочу плитку. Я в настоящее время использую следующие на мой взгляд, чтобы отобразить растровое изображение:Android Tile Bitmap

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

я принципиально хочу использовать растровое изображение в качестве фонового изображения в мое приложение, и хотел бы повторить растровое изображение в обоих X и Y. ,

Я видел константу TileMode.REPEAT для класса BitmapShader, но я не уверен, что это нужно использовать для повторения фактического растрового изображения или используется для применения фильтра к растровому изображению.

+0

Кто-нибудь знает, как это сделать в Java-коде без использования xml? – endryha

ответ

123

Вы должны сделать это в xml вместо java-кода. Я сам этого не делал, но я нашел этот пример.

<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" 
> 

затем в XML называется backrepeat.xml

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

reference

+2

просто добавить, backrepeat.xml отправляется в папку «drawable» –

+2

Это не сработает для рисования на холсте, хотя ... – stealthcopter

+0

Может быть, это педант здесь, но первая строка должна читать - Neil

15

backrepeat.xml выше глючит

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

Почему это глючит и как это исправить? –

+0

Это добавляет: android: dither = "true", который ничего не делает, если плитка не работает хорошо, чтобы начать с. –

34

Разобрался версию кода:

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

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

Тогда, если у вас есть вытяжка для плитки, это может быть использовано вместо того, чтобы сделать BitmapDrawable:

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

Это отлично работает, но как бы вы повторили его только по вертикали? Я попытался удалить setTileModeX, но тогда он даже не работает вообще. –

+0

@WilliamL. Странный. [Docs] (http://developer.android.com/reference/android/graphics/drawable/BitmapDrawable.html#setTileModeX (android.graphics.Shader.TileMode)), похоже, говорит, что он должен работать только с одним из них , Лучше всего попробовать попробовать ['Shader.TileMode.CLAMP'] (http://developer.android.com/reference/android/graphics/Shader.TileMode.html) и посмотреть, что произойдет. – Izkata

+0

Он работает, если я повторяю его только по горизонтали, но не только по вертикали. И CLAMP делает то же самое, что не устанавливает режим плитки в первую очередь. –

5

Кажется, что некоторые люди заинтересованы в этом в представлении, в методе OnDraw. Следующий код работает для меня:

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

Он заполнит всю площадь. Последняя плитка может быть не полной, справа/снизу больше всего экрана будет потянуто. – kgiannakakis

+0

Я использовал этот сегмент только для своего холста, а не для всего, поэтому, очевидно, вы получаете лишнее начертание, тогда ширина и высота не делятся на изображение. Я удалил свой комментарий, поскольку он не имеет отношения к вопросу. Сожалею! – stealthcopter

+0

В этом случае вы использовали бы BitmapDrawable.setBounds и 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" 
> 

Это работало отлично для меня. Мне не нужно было создавать битмап отдельно. Я использовал атрибут tileMode в макете.

+0

Спасибо, я нашел, что это самый простой подход. – patrickandroid

0

Если вы хотите повторить фон только вертикально, вы можете установить ширину вашего макета как «wrap_content», тогда как если вы хотите, чтобы фон повторялся горизонтально, установите высоту на «wrap_content». Если и высота, и ширина установлены на «fill_parent», тогда она будет чередоваться в направлениях X и Y.

Например, следующий код будет повторять фон по вертикали:

<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

Просто поместите эту строку кодов в 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); 
} 

}