Android自定義VIew實現(xiàn)衛(wèi)星菜單效果淺析
一 概述:
最近一直致力于Android自定義VIew的學(xué)習(xí),主要在看《android群英傳》,還有CSDN博客鴻洋大神和wing大神的一些文章,寫的很詳細,自己心血來潮,學(xué)著寫了個實現(xiàn)了類似衛(wèi)星效果的一個自定義的View,分享到博客上,望各位指點一二。寫的比較粗糙,見諒。(因為是在Linux系統(tǒng)下寫的,效果圖我直接用手機拍的,難看,大家講究下就看個效果,勿噴)。
先來看個效果圖,有點不忍直視:

自定義VIew準備:
(1)創(chuàng)建繼承自View的類;
(2)重寫構(gòu)造函數(shù);
(3)定義屬性。
(4)重寫onMeasure(),onLayout()方法。
好了,廢話不說了,準備上菜。
二 相關(guān)實現(xiàn)
首先是自定義的View,重寫構(gòu)造函數(shù),我這里是直接繼承的VIewGroup,貼上代碼:
public MoonView(Context context) {
this(context,null);
}
public MoonView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public MoonView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
這里需要讀取自定義的屬性,所以調(diào)用含三個參數(shù)的構(gòu)造函數(shù)。
自定義的屬性,我這里知定義了兩個,一個是菜單弧形的半徑,還有個是菜單在屏幕的位置,這里可以設(shè)置在左上角,左下角,右上角,右下角。代碼如下:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MoonAttrs"> <attr name="mRadius" format="integer"></attr><!--菜單圓形半徑--> <attr name="mPosition"><!--衛(wèi)星菜單屏幕所在位置--> <enum name="leftTop" value="-2"></enum><!--左上角--> <enum name="leftBottom" value="-1"></enum><!--左下角--> <enum name="rightTop" value="-3"></enum><!--右上角--> <enum name="rightBottom" value="-4"></enum><!--右下角--> </attr> </declare-styleable> </resources>
然后在布局文件里面引用自定義的View,配置屬性:
<?xml version="1.0" encoding="utf-8"?> <com.example.liujibin.testmyview3.myView.MoonView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.com/apk/res/com.example.liujibin.testmyview3" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" custom:mRadius="400" custom:mPosition="rightBottom" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/sapi_icon_add_account"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/sapi_icon_add_account"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/sapi_icon_add_account"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/sapi_icon_add_account"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/sapi_icon_add_account"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@mipmap/sapi_icon_add_account"/> </com.example.liujibin.testmyview3.myView.MoonView>
最后我們需要在自定義的View類中的構(gòu)造函數(shù)里,獲取相關(guān)的屬性值:
public MoonView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//獲取相關(guān)屬性
TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MoonAttrs,
defStyleAttr,0);
mRaius = ta.getInt(R.styleable.MoonAttrs_mRadius,500);
position = ta.getInt(R.styleable.MoonAttrs_mPosition,-1);
}
做完以上的準備工作,我們就可以對組件進行測量,布局。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
count = getChildCount()-1;
angle = 90/(count-1);
int count = getChildCount();
for(int i =0;i< count;i++){
measureChild(getChildAt(i),widthMeasureSpec,heightMeasureSpec);
}
}
count獲取按鈕的數(shù)量,有一個是中心點,不參與計算,angle是每個按鈕離基準線的角度,這里以90度為準,固定在這個范圍里面均勻分配。
首先先把中心點固定好位置:
@Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
if(isChanged){
layoutBottom();
}
}
private void layoutBottom(){
View view = getChildAt(0);
switch (position){
case -1:
btml = 0;
btmt = getMeasuredHeight() - view.getMeasuredHeight();
btmr = view.getMeasuredWidth();
btmb = getMeasuredHeight();
break;
case -2:
btml = 0;
btmt = 0;
btmr = view.getMeasuredWidth();
btmb = view.getMeasuredHeight();
break;
case -3:
btml = getMeasuredWidth() - view.getMeasuredWidth();
btmt = 0;
btmr = getMeasuredWidth();
btmb = view.getMeasuredHeight();
break;
case -4:
btml = getMeasuredWidth() - view.getMeasuredWidth();
btmt = getMeasuredHeight() - view.getMeasuredHeight();
btmr = getMeasuredWidth();
btmb = getMeasuredHeight();
break;
}
btmWidth = view.getMeasuredWidth();
btmHeight = view.getMeasuredHeight();
view.setOnClickListener(this);
view.layout(btml,btmt,btmr,btmb);
}
position的值看屬性就明白了,對中心點進行固定位置。并且注冊點擊事件。
現(xiàn)在開始給剩下的按鈕布局,并隱藏按鈕:
@Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
if(isChanged){
layoutBottom();
int count = getChildCount();
for(int k = 0;k < count - 1;k++){
View view = getChildAt(k+1);
int childWidth = view.getMeasuredWidth();
int childHeight = view.getMeasuredHeight();
int childX = (int)(mRaius*(Math.sin(angle*(k)*Math.PI/180)));
int childY = (int)(mRaius*(Math.cos(angle*(k)*Math.PI/180)));
int left = 0;
int top = 0;
int right = 0;
int bottom = 0;
switch(position){
case -1:
left = childX+btmWidth/2-childWidth/2;
top =getMeasuredHeight() - (childY+childHeight/2+btmHeight/2);
right = childX+btmWidth/2+childWidth/2;
bottom =getMeasuredHeight() - (childY + btmHeight/2) + childHeight/2;
break;
case -2:
left = childX+btmWidth/2-childWidth/2;
top =childY-childHeight/2+btmHeight/2;
right = childX+btmWidth/2+childWidth/2;
bottom = childY + btmHeight/2 + childHeight/2;
break;
case -3:
left = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2);
top =childY-childHeight/2+btmHeight/2;
right = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2)+childWidth;
bottom = childY + btmHeight/2 + childHeight/2;
break;
case -4:
left = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2);
top =getMeasuredHeight() - (childY+childHeight/2+btmHeight/2);
right = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2)+childWidth;
bottom =getMeasuredHeight() - (childY + btmHeight/2) + childHeight/2;
break;
}
view.layout(left,top,right,bottom);
view.setVisibility(View.GONE);
}
}
}
現(xiàn)在我們實現(xiàn)點擊事件:
@Override
public void onClick(View view) {
if(isChanged){
int count = getChildCount();
for(int i = 0;i < count - 1;i++){
View childView = getChildAt(i+1);
int childX = (int)(mRaius*(Math.sin(angle*(i)*Math.PI/180)));
int childY = (int)(mRaius*(Math.cos(angle*(i)*Math.PI/180)));
int childWidth = view.getMeasuredWidth();
int childHeight = view.getMeasuredHeight();
int left = 0;
int top = 0;
TranslateAnimation ta = null;
switch(position){
case -1:
left = childX+btmWidth/2-childWidth/2;
top =getMeasuredHeight() - (childY+childHeight/2+btmHeight/2);
ta = new TranslateAnimation(-(left+childView.getMeasuredWidth()),0,getMeasuredHeight()-top,0);
break;
case -2:
left = childX+btmWidth/2-childWidth/2;
top =childY-childHeight/2+btmHeight/2;
ta = new TranslateAnimation(-(left+childView.getMeasuredWidth()),0,-top,0);
break;
case -3:
left = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2);
top =childY-childHeight/2+btmHeight/2;
ta = new TranslateAnimation(getMeasuredWidth()-(left+childView.getMeasuredWidth()),0,-top,0);
break;
case -4:
left = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2);
top =getMeasuredHeight() - (childY+childHeight/2+btmHeight/2);
ta = new TranslateAnimation(getMeasuredWidth()-(left+childView.getMeasuredWidth()),0,getMeasuredHeight()-top,0);
break;
}
ta.setDuration(500);
childView.setAnimation(ta);
childView.setVisibility(View.VISIBLE);
}
isChanged = false;
}else{
int count = getChildCount();
for(int i = 0;i < count - 1;i++){
View childView = getChildAt(i+1);
int childX = (int)(mRaius*(Math.sin(angle*(i)*Math.PI/180)));
int childY = (int)(mRaius*(Math.cos(angle*(i)*Math.PI/180)));
int childWidth = view.getMeasuredWidth();
int childHeight = view.getMeasuredHeight();
int left = 0;
int top = 0;
TranslateAnimation ta = null;
switch(position){
case -1:
left = childX+btmWidth/2-childWidth/2;
top =getMeasuredHeight() - (childY+childHeight/2+btmHeight/2);
ta = new TranslateAnimation(0,-(left+childView.getMeasuredWidth()),0,getMeasuredHeight()-top);
break;
case -2:
left = childX+btmWidth/2-childWidth/2;
top =childY-childHeight/2+btmHeight/2;
ta = new TranslateAnimation(0,-(left+childView.getMeasuredWidth()),0,-top);
break;
case -3:
left = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2);
top =childY-childHeight/2+btmHeight/2;
ta = new TranslateAnimation(0,getMeasuredWidth()-(left+childView.getMeasuredWidth()),0,-top);
break;
case -4:
left = getMeasuredWidth() - (childX+btmWidth/2+childWidth/2);
top =getMeasuredHeight() - (childY+childHeight/2+btmHeight/2);
ta = new TranslateAnimation(0,getMeasuredWidth()-(left+childView.getMeasuredWidth()),0,getMeasuredHeight()-top);
break;
}
ta.setDuration(500);
childView.setAnimation(ta);
childView.setVisibility(View.GONE);
}
isChanged = true;
}
}
設(shè)置點擊顯示以及隱藏,并且?guī)эh動的動畫效果。
四個角落效果如下:




以上所述是小編給大家介紹的Android自定義VIew實現(xiàn)衛(wèi)星菜單效果淺析,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
- Android 自定義組件衛(wèi)星菜單的實現(xiàn)
- Android衛(wèi)星菜單效果的實現(xiàn)方法
- Android實現(xiàn)自定義的衛(wèi)星式菜單(弧形菜單)詳解
- Android編程實現(xiàn)仿優(yōu)酷圓盤旋轉(zhuǎn)菜單效果的方法詳解【附demo源碼下載】
- Android學(xué)習(xí)教程之圓形Menu菜單制作方法(1)
- Android自定義view實現(xiàn)圓形與半圓形菜單
- Android圓形旋轉(zhuǎn)菜單開發(fā)實例
- Android自定義ViewGroup實現(xiàn)帶箭頭的圓角矩形菜單
- Android仿優(yōu)酷圓形菜單學(xué)習(xí)筆記分享
- Adapter模式實戰(zhàn)之重構(gòu)鴻洋集團的Android圓形菜單建行
- Android實現(xiàn)衛(wèi)星菜單效果
相關(guān)文章
Android 優(yōu)化之卡頓優(yōu)化的實現(xiàn)
這篇文章主要介紹了Android 優(yōu)化之卡頓優(yōu)化的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07
android PopupWindow 和 Activity彈出窗口實現(xiàn)方式
本人小菜一個。目前只見過兩種彈出框的實現(xiàn)方式,第一種是最常見的PopupWindow,第二種也就是Activity的方式是前幾天才見識過,需要的朋友可以參考下2012-11-11
詳解Android 基于TCP和UDP協(xié)議的Socket通信
這篇文章主要介紹了詳解Android 基于TCP和UDP協(xié)議的Socket通信,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-11-11
Android實現(xiàn)圖片循環(huán)播放的實例方法
2013-05-05
Android BSearchEdit 搜索結(jié)果選擇框的實例代碼
EditText搜索結(jié)果下拉框、自動or回調(diào)模式、可diy、使用超簡便。這篇文章主要介紹了Android BSearchEdit 搜索結(jié)果選擇框的實例代碼,需要的朋友可以參考下2019-10-10
教你3分鐘了解Android 簡易時間軸的實現(xiàn)方法
本篇文章主要介紹了教你3分鐘了解Android 簡易時間軸的實現(xiàn)方法,具有一定的參考價值,有興趣的可以了解一下2017-07-07

