這些日子一直想自己在安卓平臺上寫個類似蘋果小白球的小程序,仗着自己會點JAVA就決定開始幹了。
然後在其中需要做一個圓形的佈局,於是在網上各種搜索,終究還是實現了。
覺得這個圓形佈局很有意思,於是有了這篇文章,新手開寫,請老師傅們多多指導。
首先我們分析一下這個圓形佈局的佈局,分成三個大的部分:
- 原點
- 以原點爲中心承載元素的圓
- 需要佈局在圓上的元素
那麼,先從這個圓來說,我們在一個佈局內(可以是RelativeLayout或LinearLayout)弄出一個圓,圓最大直徑爲佈局寬高中的最小值。如下圖:
最外圍的深灰色長方形爲我們的佈局;紅色圓爲佈局內最大的圓;
黃色小圓,爲中心元素;分佈四周的8個綠色的爲參與圓形佈局的子元素。
其中o爲原點(圓心),oa爲圓的半徑,ab爲佈局的高度,也就是圓的直徑。
角aor的角度爲360/8;
以oa爲起點,oa至or的弧度爲(2 * Math.PI / 360) * (360 / 8) * 1;
爲了參與圓形佈局的元素不跑到我們的佈局外面,
所以在計算位置時,圓的半徑應該爲or = oa – 元素寬度/2;所以圖中灰色圓,纔是我們真正計算時使用到的圓。
現在我們要計算黃色圓的XY座標值,通過getX();getY();我們能獲取到中心元素左上角的XY座標值,即下圖中m的位置;
那麼中心元素元心的位置則爲o.x = m.x + 中心元素寬度/2;o.y = m.y + 中心元素高度/2;
假設m的xy爲{0,0},中心元素的寬度爲50,高度爲50,那麼中心元素中心點的xy爲{0+50/2,0+50/2},即中心元素中心位置的XY座標爲{25,25},同理,其他各個分佈在圓上的子元素的中心位置也以此類推。
佈局分析先到這兒,我們接下來直接上代碼,在代碼裏,我們以6個元素參與圓形佈局爲例。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.demo.MainActivity">
<RelativeLayout
android:id="@+id/circle_layout"
android:layout_width="300dp"
android:layout_height="200dp"
android:background="#837f7f"
android:layout_centerInParent="true"
>
<Button
android:id="@+id/btn_000"
android:layout_width="60dp"
android:layout_height="60dp"
android:text="0"
/>
<Button
android:id="@+id/btn_001"
android:layout_width="60dp"
android:layout_height="60dp"
android:text="1"
/>
<Button
android:id="@+id/btn_002"
android:layout_width="60dp"
android:layout_height="60dp"
android:text="2"
/>
<Button
android:id="@+id/btn_003"
android:layout_width="60dp"
android:layout_height="60dp"
android:text="3"
/>
<Button
android:id="@+id/btn_004"
android:layout_width="60dp"
android:layout_height="60dp"
android:text="4"
/>
<Button
android:id="@+id/btn_005"
android:layout_width="60dp"
android:layout_height="60dp"
android:text="5"
/>
<Button
android:id="@+id/client_btn"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_margin="50dp"
android:layout_centerInParent="true"
android:text="中"
android:background="@xml/shape"
/>
</RelativeLayout>
</RelativeLayout>
代碼效果如下圖:
我們要以”中”這個中心元素,在灰色佈局類範圍內,將另外6個子元素進行圓形佈局,爲了省事,我沒有將6個子元素再做佈局,直接堆一塊兒了。
我們先獲取佈局內除“中”元素以外的其他6個子元素,代碼:
/**
* 獲取指定元素下的子元素
* @param parentView
* @return
*/
private List<View> getChildView(ViewGroup parentView){
List<View> views = new ArrayList<View>();
int child_count = parentView.getChildCount() - 1;//排除掉中心元素
String packageName = getApplicationContext().getPackageName();//獲取當前應用包名
View view;
String id_name;
Integer id;
for (int i = 0; i< child_count; i++){
id_name = "btn_00" + i; //拼接ID名稱
/**
因爲懶,所以用了循環去找元素,前提是元素ID有規律
當然,也可以用getChilds()的方式獲取所有子元素,再排除掉中心元素
*/
id = getResources().getIdentifier(id_name, "id", packageName);//根據ID名稱獲取ID值
view = findViewById(id);//根據ID找元素
views.add(view);//添加元素
}
return views;
}
找完子元素,再將這6個子元素相對“中”元素進行佈局,代碼:
/**
* 創建圓形佈局
* @param clientView 圓形佈局的中心元素
* @param views 參與圓形佈局的元素
*/
private void createCircleLayout(View clientView,List<View> views){
//大圓的中心
int[] location = new int[2] ;
location[0] = (int) clientView.getX();//獲取中心元素相對父級的X座標
location[1] = (int) clientView.getY();//獲取中心元素相對父級的Y座標
//當前中心元素的X座標
Double zeroX = Double.valueOf(location[0]);
//X座標加元素寬度的一半,則爲元素X的中心座標
zeroX = zeroX + clientView.getWidth()/2;
//當前中心元素的Y座標
Double zeroY = Double.valueOf(location[1]);
//Y座標加中心元素高度的一半,則爲元素Y的中心座標
zeroY = zeroY + clientView.getHeight()/2;
/**
* 以上定下了圓的中心座標
*/
/**
* 獲取圓的半徑
* 1.獲取當前中心元素的父元素
* 2.計算父元素內圓的最大半徑
*/
View clientViewParent = (View) clientView.getParent();
Integer radius = Math.min(clientViewParent.getWidth(), clientViewParent.getHeight()) / 2;
//參與圓形佈局的元素數量
int count = views.size();
View child_view;
//定義弧度,計算子項在圓上位置時需要用到
Double hudu = 0d;
//根據子項的數量,計算每個子項間的平均角度
Double angleDelay = 360d / count;
Double tmpX;//子項X位置
Double tmpY;//子項Y位置
for (int i = 0; i<count; i++){
child_view = views.get(i);
Integer tmp_radius = radius - Math.max(child_view.getWidth(),child_view.getHeight()) / 2;
//循環計算每一個子項的弧度
hudu = (2 * Math.PI / 360) * angleDelay * i;
tmpX = zeroX + Math.sin(hudu) * tmp_radius;//計算子項的X座標
tmpY = zeroY - Math.cos(hudu) * tmp_radius;//計算子項的Y座標
tmpX = tmpX - child_view.getWidth() / 2; //計算子項的中心點X座標
tmpY = tmpY - child_view.getHeight() / 2;//計算子項的中心點Y座標
child_view.setBackgroundDrawable(clientView.getBackground());//將中心元素的圓形樣式copy給子元素
child_view.setX(tmpX.intValue()); //設置子項的X座標
child_view.setY(tmpY.intValue()); //設置子項的Y座標
}
}
最後呢,我們將圓形佈局綁定在“中”元素的點擊事件上,代碼:
Button button = (Button) findViewById(R.id.client_btn);
button.setOnClickListener(new ClientBtnOnClick());
class ClientBtnOnClick implements View.OnClickListener{
@Override
public void onClick(View v) {
//需要圓形佈局的元素
ViewGroup circle_layout = (ViewGroup) findViewById(R.id.circle_layout);
//獲取子元素
List<View> views = getChildView(circle_layout);
//對子元素進行圓形佈局
createCircleLayout(v,views);
}
}
上下極簡效果圖
最後上下稍微漂亮點的效果圖
大家若是有什麼不懂或需要指正的,可以在下面評論區中留言哈,我看到後會回的,另外對android有興趣的同學可以加我們程序員劉某人的羣:555974449,羣裏面有很多大神的,而且很熱情,很熱心的,大家不懂的可以問的。