C语言六边形蜂巢数组,android 六边形蜂巢布局控件
前言:最近新項(xiàng)目有個(gè)需求,實(shí)現(xiàn)蜂巢一樣的布局界面。剛看到需求,心里臥槽了下,不過還挺好看的,于是思考了怎么實(shí)現(xiàn)。花了兩三天時(shí)間,終于實(shí)現(xiàn)了跟我想要的差不多,封裝成了比較容易拓展的使用方式。
需求效果如下:
1.蜂巢類型:
與正常圖片切換效果:
下面是實(shí)現(xiàn)思路:
怎么實(shí)現(xiàn)呢,認(rèn)真觀察,我們會(huì)發(fā)現(xiàn)其實(shí)整個(gè)視圖單個(gè)item是按照這樣的規(guī)律排布六邊形挨著連接,:
所以我們的解決問題就轉(zhuǎn)化為如何按照這樣的規(guī)律排布。該界面復(fù)雜就復(fù)雜在一個(gè)一正六邊形挨著連接,計(jì)算六邊形的邊以及點(diǎn),顯然會(huì)比較復(fù)雜,為了將問題簡單化,我將正六邊形轉(zhuǎn)化為正方形,要知道,正六邊形可以通過正方形的內(nèi)切圓繪制出來:
所以這樣就很簡單了,上面的排布其實(shí)轉(zhuǎn)化為正方形的排布了:
所以我們最終實(shí)現(xiàn)的思路是這樣的: 繪制正方形區(qū)域并按照規(guī)律排布,在正方形區(qū)域繪制出正六邊形。
接下來是實(shí)現(xiàn)過程
實(shí)現(xiàn)正方形按照指定規(guī)律排布,第一時(shí)間想到的是使用RecyclerView并重寫RecyclerView.LayoutManager。關(guān)于RecyclerView不懂的請(qǐng)百度。
如何計(jì)算正方形排布的坐標(biāo),首先,我將一組視圖分成了兩小組:
為了拓展性,我們可以指定要顯示的列數(shù)mColumnSize,這樣我們就可以計(jì)算出第一小組最多顯示個(gè)數(shù)以及第二小組最多顯示個(gè)數(shù):
int rvwidth = getRecyclerViewWidth();//RecyclerView width
int itemWidth = rvwidth / mColumnSize;//正方形寬度
int itemHeight = itemWidth;
int firstgroupnum = mColumnSize / 2 ;//第一小組最多顯示個(gè)數(shù)
int secondgroupnum = mColumnSize % 2 == 0 ? mColumnSize / 2 : mColumnSize / 2 + 1;//第二組最多顯示個(gè)數(shù)
這樣我們可以得到了內(nèi)切圓半徑R:
float r = itemWidth / 2;//內(nèi)切圓半徑
整個(gè)組邊的計(jì)算關(guān)系如下圖:
我們很容易就得到以下關(guān)系:
w = r
fleft = (rvwidth - (itemWidth * firstgroupnum + r * (firstgroupnum - 1))) / 2;//第一組開始偏移量
sright = fleft-itemWidth*3/4;//第二組開始偏移量
通過上面的關(guān)系我們很容易就得到了這些正方形的分布坐標(biāo)。那么開始擼代碼了。
為了簡單易于理解,封裝一下每一組的數(shù)據(jù),每一組的數(shù)據(jù)由兩小組數(shù)據(jù)組成:
private class GroupData{
int itemIndex = 0;
List FirstGroup = new ArrayList<>();
List SecondGroup = new ArrayList<>();
}
private class GroupItem{
Rect rect = null;
int itemindex = 0;
}
這樣我們就可以根據(jù)第一小組顯示的個(gè)數(shù)與第二小組顯示的個(gè)數(shù)得到劃分好的GroupData:
/** 將數(shù)據(jù)轉(zhuǎn)化為組數(shù)據(jù) *@param firstgroupnum 第一小組最多顯示個(gè)數(shù) *@param secondgroupnum 第二小組最多顯示個(gè)數(shù) *@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;
}
轉(zhuǎn)化為組數(shù)據(jù)后,計(jì)算出上面的邊關(guān)系:
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)));//六邊形到邊到內(nèi)切圓的距離
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);
}
}
注意的是,為了方便使用,我們對(duì)每組的視圖增加了間距,每組的兩個(gè)小組之間也增加了間距。
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);
}
}
}
完成到這里后,我們就可以實(shí)現(xiàn)到這樣的效果了:
間距為50顯示5列的效果:
間距為50顯示7列的效果:
剩下的最后一步,就是將正方形圖片轉(zhuǎn)化為正六邊形而已,具體實(shí)現(xiàn)代碼,參考我這篇文章:android六邊形imageview
最終轉(zhuǎn)化后得到效果如下:
總結(jié)
以上是生活随笔為你收集整理的C语言六边形蜂巢数组,android 六边形蜂巢布局控件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html无序列表标签有哪些(怎么设在ht
- 下一篇: 英雄无敌5有哪些秘籍