2014-04-15 73 views
7

一個蜂箱佈局應該像這樣可能在Android中創建一個蜂巢式XML佈局?

彩色蜂巢只是讓您瞭解我是如何放下元素。

其中Layout插件你建議使用哪?

我試過GridView,但我不能製作這樣的單元格,然後FrameLayout,但不想在設置配置單元位置時處理像素(或dp)值。

我在我的智慧結束。我接近於這樣的結論:類似這樣的事情不能以高質量的方式在Android上完成,並且不使用類似遊戲的庫。我希望有人會給我一個解決方案的好線索。

+1

你真的引起了我的好奇心,我做了一些Google搜索,想知道是否有可能。一切都表明不,它不是(不是通過簡單的方式),非矩形佈局只能通過「作弊」來實現,如http://stackoverflow.com/a/13879492/168719或http:///stackoverflow.com/a/19583072/168719 - 換句話說,它們只會顯示爲非矩形,並且在透明區域點擊只會被忽略以保持這種印象。在你的情況下,雖然它必須委託給相鄰的tile,並且必須處理這會使代碼更加複雜。 –

+0

你可能通過繼承一個'View',用六角形'Path'繪製出蜂箱,使用'offset()'方法迭代行,用_slightly_不同的RGB值填充它們,然後檢查來自'onTouchEvent()'中的座標的值? (另外,我認爲這更像是一種蜂窩形狀,這是合適的。) –

+1

我想你也可以通過簡單的數字運算來確定觸摸所處的區域,但這比我想要做的更多。 __編輯:__有人已經做了數學,並用Java編寫! http://www.gdreflections.com/2011/02/hexagonal-grid-math.html –

回答

6

由於我不確定預期的目的或要求,以下僅僅是概念驗證。 HoneycombView類沒有真正的非法參數檢查或任何類型的異常處理。大多數屬性都是「硬編碼」的,比如牆的顏色和寬度,單元格的顏色和方向等等。這些都可以通過添加適當的setter和getter來輕鬆修改。 我已經包含一個簡單的Activity類來演示它的用法。

public class HoneycombView extends View 
{ 
    private Paint wallPaint = new Paint(); 
    private Paint fillPaint = new Paint(); 
    private Paint cachePaint = new Paint(); 
    private Path combPath; 
    private Bitmap cacheBmp; 
    private Canvas cacheCan; 

    private int cellWidth; 
    private int columns; 
    private int rows; 
    private boolean[][] cellSet; 

    private OnCellClickListener listener; 

    public HoneycombView(Context context) 
    { 
     this(context, null); 
    } 

    public HoneycombView(Context context, AttributeSet attrs) 
    { 
     super(context, attrs); 

     wallPaint.setColor(Color.YELLOW); 
     wallPaint.setStyle(Paint.Style.STROKE); 
     wallPaint.setStrokeWidth(5f); 

     fillPaint.setStyle(Paint.Style.FILL);  
     cachePaint.setStyle(Paint.Style.FILL); 
    } 

    public void initialize(int columns, int rows) 
    { 
     this.columns = columns; 
     this.rows = rows; 

     this.cellSet = new boolean[columns][rows]; 
    } 

    public interface OnCellClickListener 
    { 
     public void onCellClick(int column, int row); 
    } 

    public void setOnCellClickListener(OnCellClickListener listener) 
    { 
     this.listener = listener; 
    } 

    public void setCell(int column, int row, boolean isSet) 
    { 
     cellSet[column][row] = isSet; 
     invalidate(); 
    } 

    public boolean isCellSet(int column, int row) 
    { 
     return cellSet[column][row]; 
    } 

    @Override 
    protected void onSizeChanged(int w, int h, int oldw, int oldh) 
    { 
     super.onSizeChanged(w, h, oldw, oldh); 

     cacheBmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); 
     cacheCan = new Canvas(cacheBmp); 

     cellWidth = 2 * w/(2 * columns + columns - 1); 
    } 

    @Override 
    protected void onDraw(Canvas canvas) 
    { 
     super.onDraw(canvas); 

     canvas.drawColor(Color.WHITE); 

     boolean oddRow; 
     int xOff; 

     combPath = getHexPath(cellWidth/2f, cellWidth/2f, (float) (cellWidth * Math.sqrt(3)/4)); 

     for (int r = 0; r < rows; r++) 
     { 
      oddRow = (r & 1) == 1; 
      xOff = 0; 

      for (int c = 0; c < columns; c++) 
      { 
       if (!(oddRow && c == columns - 1)) 
       { 
        fillPaint.setColor(cellSet[c][r] ? Color.RED : Color.WHITE); 
        canvas.drawPath(combPath, fillPaint); 

        canvas.drawPath(combPath, wallPaint); 

        cachePaint.setColor(Color.argb(255, 1, c, r)); 
        cacheCan.drawPath(combPath, cachePaint); 

        combPath.offset((int) (1.5f * cellWidth), 0); 
        xOff += 1.5f * cellWidth; 
       } 
      } 

      combPath.offset(-xOff + (oddRow ? -1 : 1) * 3 * cellWidth/4, (float) (cellWidth * Math.sqrt(3)/4)); 
     } 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent event) 
    { 
     if (event.getAction() != MotionEvent.ACTION_DOWN) 
      return true; 

     int pixel = cacheBmp.getPixel((int) event.getX(), (int) event.getY()); 

     int r = Color.red(pixel); 
     if (r == 1) 
     { 
      int g = Color.green(pixel); 
      int b = Color.blue(pixel); 

      if (listener != null) 
      { 
       listener.onCellClick(g, b); 
      } 
     } 
     return true; 
    } 

    private Path getHexPath(float size, float centerX, float centerY) 
    { 
     Path path = new Path(); 

     for (int j = 0; j <= 6; j++) 
     { 
      double angle = j * Math.PI/3; 
      float x = (float) (centerX + size * Math.cos(angle)); 
      float y = (float) (centerY + size * Math.sin(angle)); 
      if (j == 0) 
      { 
       path.moveTo(x, y); 
      } 
      else 
      { 
       path.lineTo(x, y); 
      } 
     } 

     return path; 
    } 
} 

而且Activity

public class MainActivity extends Activity 
implements HoneycombView.OnCellClickListener 
{ 
    HoneycombView honey; 

    @Override 
    public void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     getWindow().requestFeature(Window.FEATURE_NO_TITLE); 

     honey = new HoneycombView(this); 
     honey.initialize(4, 8); 
     honey.setOnCellClickListener(this); 

     setContentView(honey); 
    } 

    @Override 
    public void onCellClick(int column, int row) 
    { 
     honey.setCell(column, row, !honey.isCellSet(column, row)); 
    } 
} 

Sample image

我和我的稍稍改變一個區域的顏色來判斷會在哪裏發生的觸摸事件初步建議,但我最終這樣做的一個成員Bitmap,所以屏幕上的顏色不受影響。從代碼中可以看出,此Bitmap中的單元格填充的方式是將Color的RGB組件中的相關單元格信息編碼。紅色分量被設置爲1以指示給定像素在相關區域內(即,在整個「蜂巢」內)。然後網格中的單元格的列和行位置將被編碼爲綠色和藍色組件,並且可以通過onTouchEvent()方法輕鬆檢索。

initialize()方法設置網格中的列和行的數量,並且在示例Activity中,它們設置爲傾向於橫向。爲了清楚起見,在我的實現中,對於面向單元的長軸是水平的,我定義了一行以組成其軸線是共線的單元。我在評論中發佈的鏈接做了不同的事情。

我幾乎忘了給信用:我得到this question的六角形Path代碼。

+0

它是可滾動的嗎? –

+0

不是這樣,但我想象你可以在沒有太多麻煩的情況下將其包裝在「ScrollView」中。雖然我沒有測試過。 –

+0

好的。我會嘗試。謝謝btw –