C语言六边形蜂巢数组,android 六边形蜂巢布局控件
前言:最近新項目有個需求,實現蜂巢一樣的布局界面。剛看到需求,心里臥槽了下,不過還挺好看的,于是思考了怎么實現。花了兩三天時間,終于實現了跟我想要的差不多,封裝成了比較容易拓展的使用方式。
需求效果如下:
1.蜂巢類型:
與正常圖片切換效果:
下面是實現思路:
怎么實現呢,認真觀察,我們會發現其實整個視圖單個item是按照這樣的規律排布六邊形挨著連接,:
所以我們的解決問題就轉化為如何按照這樣的規律排布。該界面復雜就復雜在一個一正六邊形挨著連接,計算六邊形的邊以及點,顯然會比較復雜,為了將問題簡單化,我將正六邊形轉化為正方形,要知道,正六邊形可以通過正方形的內切圓繪制出來:
所以這樣就很簡單了,上面的排布其實轉化為正方形的排布了:
所以我們最終實現的思路是這樣的: 繪制正方形區域并按照規律排布,在正方形區域繪制出正六邊形。
接下來是實現過程
實現正方形按照指定規律排布,第一時間想到的是使用RecyclerView并重寫RecyclerView.LayoutManager。關于RecyclerView不懂的請百度。
如何計算正方形排布的坐標,首先,我將一組視圖分成了兩小組:
為了拓展性,我們可以指定要顯示的列數mColumnSize,這樣我們就可以計算出第一小組最多顯示個數以及第二小組最多顯示個數:
int rvwidth = getRecyclerViewWidth();//RecyclerView width
int itemWidth = rvwidth / mColumnSize;//正方形寬度
int itemHeight = itemWidth;
int firstgroupnum = mColumnSize / 2 ;//第一小組最多顯示個數
int secondgroupnum = mColumnSize % 2 == 0 ? mColumnSize / 2 : mColumnSize / 2 + 1;//第二組最多顯示個數
這樣我們可以得到了內切圓半徑R:
float r = itemWidth / 2;//內切圓半徑
整個組邊的計算關系如下圖:
我們很容易就得到以下關系:
w = r
fleft = (rvwidth - (itemWidth * firstgroupnum + r * (firstgroupnum - 1))) / 2;//第一組開始偏移量
sright = fleft-itemWidth*3/4;//第二組開始偏移量
通過上面的關系我們很容易就得到了這些正方形的分布坐標。那么開始擼代碼了。
為了簡單易于理解,封裝一下每一組的數據,每一組的數據由兩小組數據組成:
private class GroupData{
int itemIndex = 0;
List FirstGroup = new ArrayList<>();
List SecondGroup = new ArrayList<>();
}
private class GroupItem{
Rect rect = null;
int itemindex = 0;
}
這樣我們就可以根據第一小組顯示的個數與第二小組顯示的個數得到劃分好的GroupData:
/** 將數據轉化為組數據 *@param firstgroupnum 第一小組最多顯示個數 *@param secondgroupnum 第二小組最多顯示個數 *@return */
private List GetGroupData(int firstgroupnum, int secondgroupnum) {
int groupnums = getItemCount()/(firstgroupnum+secondgroupnum);
if(getItemCount()%(firstgroupnum+secondgroupnum)!=0){
groupnums++;
}
List groupdata = new ArrayList<>();
int ItemIndex = 0;
for(int index = 0;index
GroupData g = new GroupData();
for(int i=0;i
GroupItem item = new GroupItem();
item.itemindex = ItemIndex++;
item.rect = mItemFrames.get(item.itemindex);
g.FirstGroup.add(item);
}
for(int i=0;i
GroupItem item = new GroupItem();
item.itemindex = ItemIndex++;
item.rect = mItemFrames.get(item.itemindex);
g.SecondGroup.add(item);
}
groupdata.add(g);
}
return groupdata;
}
轉化為組數據后,計算出上面的邊關系:
float fleft = (rvwidth - (itemWidth * firstgroupnum + r * (firstgroupnum - 1))) / 2;//第一組開始偏移量
float firstgroupitemleftposition = 0;//第一組item左邊位置
float sright = fleft-itemWidth*3/4;//第二組開始偏移量
float d = (float) (itemHeight / 4 * (2 - Math.sqrt(3)));//六邊形到邊到內切圓的距離
float secondgroupmarginfirstgroup = (float) itemHeight/2 - d;
float topmargin = 50;
float toppositoion = 0;
然后遍歷排布每組的正方形,每組的正方形有兩小組,分別遍歷排布:
for(int index =0;index
toppositoion = index*itemHeight+topmargin+GROUP_PADDING*index;
toppositoion = toppositoion-d*2*index;
GroupData g = groupDatas.get(index);
for(int firstgroupindex =0;firstgroupindex
int left = (int) (fleft+firstgroupindex*(itemWidth+r));
int top = (int) toppositoion;
int right = left+itemWidth;
int bottom = top+itemHeight;
Rect rect = g.FirstGroup.get(firstgroupindex).rect;
rect.set(left,top,right,bottom);
}
toppositoion = toppositoion+secondgroupmarginfirstgroup+FIRSTGROUP_MARGIN_SECONDGROUP;
for(int secondgroupindex =0;secondgroupindex
int left = (int) (sright+secondgroupindex*(itemWidth+r));
int top = (int) toppositoion;
int right = left+itemWidth;
int bottom = top+itemHeight;
Rect rect = g.SecondGroup.get(secondgroupindex).rect;
rect.set(left,top,right,bottom);
}
}
注意的是,為了方便使用,我們對每組的視圖增加了間距,每組的兩個小組之間也增加了間距。
public int FIRSTGROUP_MARGIN_SECONDGROUP = 50;//第一小組與第二小組間距
public int GROUP_PADDING = 120;//組距
分布好后,填充視圖就是了:
private void fill(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (getItemCount() <= 0 || state.isPreLayout()) {
return;
}
Rect displayRect = new Rect(mHorizontalOffset, mVerticalOffset,
getHorizontalSpace() + mHorizontalOffset,
getVerticalSpace() + mVerticalOffset);
for (int i = 0; i < getItemCount(); i++) {
Rect frame = mItemFrames.get(i);
if (Rect.intersects(displayRect, frame)) {
View scrap = recycler.getViewForPosition(i);
addView(scrap);
measureChildWithMargins(scrap, 0, 0);
layoutDecorated(scrap, frame.left - mHorizontalOffset, frame.top - mVerticalOffset,
frame.right - mHorizontalOffset, frame.bottom - mVerticalOffset);
}
}
}
完成到這里后,我們就可以實現到這樣的效果了:
間距為50顯示5列的效果:
間距為50顯示7列的效果:
剩下的最后一步,就是將正方形圖片轉化為正六邊形而已,具體實現代碼,參考我這篇文章:android六邊形imageview
最終轉化后得到效果如下:
總結
以上是生活随笔為你收集整理的C语言六边形蜂巢数组,android 六边形蜂巢布局控件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html无序列表标签有哪些(怎么设在ht
- 下一篇: c语言中全局变量内存,C语言——全局变量