国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android衛(wèi)星菜單效果的實現(xiàn)方法

2019-10-23 18:27:38
字體:
來源:轉載
供稿:網(wǎng)友

Android小白第一次寫博客,心情無比激動。下面給大家展示一下衛(wèi)星菜單的實現(xiàn)。

1.簡單介紹衛(wèi)星菜單

在應用程序中,有很多展示菜單的方式,但其功能都是大同小異,這樣一來,菜單的美觀以及展示方式就顯的尤為重要,衛(wèi)星菜單就是很不錯的一種。下面是本案例的gif圖:

android,衛(wèi)星菜單

2.學習本案例需要的知識點

(1)動畫

(2)自定義ViewGroup

(3)自定義屬性

a、attr.xml

b、在布局中使用自定義屬性

c、在代碼中獲取自定義屬性值

3.首先分析我們的衛(wèi)星菜單需要那些自定義屬性并書寫代碼

首先,菜單可以顯示在屏幕的四個角,所以我們需要一個屬性來確定它的位置,菜單在屏幕的四個角比較美觀,在這里用到枚舉。

其次,我們還需要一個展開半徑,因此還需要自定義半徑。

下面是attr.xml

<?xml version="1.0" encoding="utf-8"?><resources> <attr name="position">  <enum name="left_top" value="0" />  <enum name="left_bottom" value="1" />  <enum name="right_top" value="2" />  <enum name="right_bottom" value="3" /> </attr> <attr name="radius" format="dimension"/> <declare-styleable name="SateMenu">  <attr name="radius" />  <attr name="position" /> </declare-styleable></resources>

4.自定義ViewGroup

–繼承ViewGroup 以相關屬性

public class SateMenu extends ViewGroup implements View.OnClickListener { private int animationTime; //動畫時間 private int radius; //展開半徑 private int pos; //從自定義屬性中獲取的菜單位置 private State state; //菜單狀態(tài) private int l = 0, t = 0; //左上值 private View centerBtn = null; //展開按鈕 private MenuItemListener menuItemListener; //菜單項點擊監(jiān)聽 private Position position; //枚舉型菜單位置 private enum Position { //位置枚舉  LEFT_TOP, LEFT_BOTTOM, RIGHT_TOP, RIGHT_BOTTOM } private enum State { //菜單狀態(tài)枚舉  OPEN, COLSE }

–構造方法

public SateMenu(Context context) {  //一個參數(shù)構造方法調(diào)用兩個參數(shù)構造方法  this(context, null); } public SateMenu(Context context, AttributeSet attrs) {  //兩個參數(shù)構造方法調(diào)用三個個參數(shù)構造方法  this(context, attrs, 0); } public SateMenu(Context context, AttributeSet attrs, int defStyleAttr) {  super(context, attrs, defStyleAttr);  animationTime = 500; //設置動畫展開時間  TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SateMenu, defStyleAttr, 0); //獲取自定義屬性值集合  radius = (int) a.getDimension(R.styleable.SateMenu_radius,    TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, getResources().getDisplayMetrics())); //獲取半徑并轉化為像素值  state = State.COLSE; //設置菜單默認關閉  pos = a.getInt(R.styleable.SateMenu_position, 0); //獲取位置  //將位置轉化為枚舉值 (這樣就把無意義的int轉化為有意義的枚舉值)  switch (pos) {   case 0:    position = Position.LEFT_TOP;    break;   case 1:    position = Position.LEFT_BOTTOM;    break;   case 2:    position = Position.RIGHT_TOP;    break;   case 3:    position = Position.RIGHT_BOTTOM;    break;  } }

–重寫onMeasure方法

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  super.onMeasure(widthMeasureSpec, heightMeasureSpec);  int count = getChildCount();  //測量子view  for (int i = 0; i < count; i++) {   measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);  } }

–重寫onLayout方法

 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) {  if (changed)   btnLayout(); } private void btnLayout() {  centerBtn = getChildAt(0);  if (position == Position.RIGHT_BOTTOM || position == Position.RIGHT_TOP) {   //如果菜單設置在屏幕的右側,那么展開按鈕的l值=ViewGroup寬度-按鈕寬度   l = getMeasuredWidth() - centerBtn.getMeasuredWidth();  }  if (position == Position.LEFT_BOTTOM || position == Position.RIGHT_BOTTOM) {   //如果菜單設置在屏幕的下邊,那么展開按鈕的t值=ViewGroup高度-按鈕高度   t = getMeasuredHeight() - centerBtn.getMeasuredHeight();  }  //設置展開按鈕位置  centerBtn.layout(l, t, l + centerBtn.getMeasuredWidth(), t + centerBtn.getMeasuredHeight());  childBtnlayout(); //設置子按鈕位置  centerBtn.setOnClickListener(this); }

–設置子按鈕位置需要一點點數(shù)學知識,下面我以主菜單在右下角為例,畫一個簡圖,圖片對應右側第一個公式

android,衛(wèi)星菜單

 private void childBtnlayout() {  int childMuneCount = getChildCount() - 1;  //角度等于90度/子按鈕個數(shù)-1  float a = (float) (Math.PI / 2 / (childMuneCount - 1));  int cl, ct; //分別是子按鈕的 左 上   for (int i = 0; i < childMuneCount; i++) {   if (position == Position.RIGHT_BOTTOM || position == Position.RIGHT_TOP) {    cl = (int) (l - radius * Math.cos(i * a));   } else {    cl = (int) (l + radius * Math.cos(i * a));   }   if (position == Position.LEFT_TOP || position == Position.RIGHT_TOP) {    ct = (int) (t + radius * Math.sin(i * a));   } else {    ct = (int) (t - radius * Math.sin(i * a));   }   View childView = getChildAt(i + 1);   childView.layout(cl, ct, cl + childView.getMeasuredWidth(), ct + childView.getMeasuredHeight());   childView.setOnClickListener(this);   childView.setTag(i);   childView.setVisibility(View.GONE);  } }

–動畫的展開與關閉,這里沒有用屬性動畫,原理是:當用戶關閉菜單的時候,將子按鈕隱藏,打開才打的時候在把子按鈕顯示出來

 private void changeState() {  int childMuneCount = getChildCount() - 1;  //設置展開按鈕旋轉動畫  Animation animation = new RotateAnimation(0, 360, centerBtn.getMeasuredWidth() / 2, centerBtn.getMeasuredHeight() / 2);  animation.setDuration(animationTime);  centerBtn.setAnimation(animation);  animation.start();  View childView;  //子按鈕有兩個動畫(位移、旋轉),所以這里用到動畫集,這里也涉及到一些數(shù)學知識,和之前設置子按鈕位置差不多  AnimationSet animationSet;  Animation translateAnimation;  Animation rotateAnimation;  int cl, ct;  float a = (float) (Math.PI / 2 / (childMuneCount - 1));  if (state == State.OPEN) {   state = State.COLSE;   for (int i = 0; i < childMuneCount; i++) {    if (position == Position.RIGHT_BOTTOM || position == Position.RIGHT_TOP)     cl = (int) (radius * Math.cos(i * a));    else     cl = (int) (-radius * Math.cos(i * a));    if (position == Position.LEFT_TOP || position == Position.RIGHT_TOP)     ct = (int) (-radius * Math.sin(i * a));    else     ct = (int) (radius * Math.sin(i * a));    childView = getChildAt(i + 1);    childView.setVisibility(View.GONE);    translateAnimation = new TranslateAnimation(0, cl, 0, ct);    translateAnimation.setDuration(animationTime);    rotateAnimation = new RotateAnimation(0, 360, childView.getMeasuredHeight() / 2, childView.getMeasuredHeight() / 2);    rotateAnimation.setDuration(animationTime);    animationSet = new AnimationSet(true);    animationSet.addAnimation(rotateAnimation);    animationSet.addAnimation(translateAnimation);    childView.setAnimation(animationSet);    animationSet.start();    childView.setVisibility(View.GONE);   }  } else {   state = State.OPEN;   for (int i = 0; i < childMuneCount; i++) {    if (position == Position.RIGHT_BOTTOM || position == Position.RIGHT_TOP)     cl = (int) (radius * Math.cos(i * a));    else     cl = (int) (-radius * Math.cos(i * a));    if (position == Position.LEFT_TOP || position == Position.RIGHT_TOP)     ct = (int) (-radius * Math.sin(i * a));    else     ct = (int) (radius * Math.sin(i * a));    childView = getChildAt(i + 1);    childView.setVisibility(View.GONE);    translateAnimation = new TranslateAnimation(cl, 0, ct, 0);    translateAnimation.setDuration(animationTime);    rotateAnimation = new RotateAnimation(360, 0, childView.getMeasuredHeight() / 2, childView.getMeasuredHeight() / 2);    rotateAnimation.setDuration(animationTime);    animationSet = new AnimationSet(true);    animationSet.addAnimation(rotateAnimation);    animationSet.addAnimation(translateAnimation);    childView.setAnimation(animationSet);    animationSet.start();    childView.setVisibility(View.VISIBLE);   }  } }

–寫到這里我們的衛(wèi)星菜單已經(jīng)可以展現(xiàn)出來的,運行一下,效果還是不錯的。美中不足的是,子按鈕還沒有點擊事件,下面我們就將這個小小的不足補充一下。我們可以通過給子按鈕添加點擊事件來監(jiān)聽它,但點擊之后要做的事情不可能寫在ViewGroup中,這就需要用接口進行回調(diào)。大家看一下在設置子按鈕位置的時候有這樣一句代碼 childView.setTag(i); 它的目的就是給子按鈕添加索引,接下來看一下具體怎樣實現(xiàn)的。

 @Override public void onClick(View v) {  if (v.getId() == centerBtn.getId()) {   changeState();  } else {   if (menuItemListener != null) {    menuItemListener.onclick((Integer) v.getTag());   }  } } public interface MenuItemListener {  void onclick(int position); } public void setMenuItemListener(MenuItemListener menuItemListener) {  this.menuItemListener = menuItemListener; }

–到這里我們已經(jīng)完全實現(xiàn)了衛(wèi)星菜單的所有功能,但大家有沒有發(fā)現(xiàn),一些菜單在展開之后,我們點擊其他區(qū)域,菜單會自動收起來,所以我們還要給我們的ViewGroup添加onTouchEvent事件,在菜單展開的時候,他把菜單收起來,并將此次點擊攔截。

 @Override public boolean onTouchEvent(MotionEvent event) {  if (state == State.OPEN) {   changeState();   return true; //攔截  }  return super.onTouchEvent(event); }

5.下面試用一下我們編寫的衛(wèi)星菜單,看一下成果。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:wzw="http://schemas.android.com/apk/res/com.satemenudemo" android:layout_width="match_parent" android:layout_height="match_parent"> <com.satemenudemo.SateMenu  android:id="@+id/menu_id"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:layout_margin="3dp"  wzw:position="right_bottom"  wzw:radius="150dp">  <ImageButton   android:id="@+id/center_btn"   android:layout_width="40dp"   android:layout_height="40dp"   android:background="@drawable/add" />  <ImageButton   android:id="@+id/menu1"   android:layout_width="wrap_content"   android:layout_height="wrap_content"   android:background="@drawable/find" />  <ImageButton   android:id="@+id/menu2"   android:layout_width="wrap_content"   android:layout_height="wrap_content"   android:background="@drawable/shop" />  <ImageButton   android:id="@+id/menu3"   android:layout_width="wrap_content"   android:layout_height="wrap_content"   android:background="@drawable/people" />  <ImageButton   android:id="@+id/menu4"   android:layout_width="wrap_content"   android:layout_height="wrap_content"   android:background="@drawable/love" /> </com.satemenudemo.SateMenu></RelativeLayout>

MainActivity.java

public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_main);  SateMenu sateMenu = (SateMenu) findViewById(R.id.menu_id);  sateMenu.setMenuItemListener(new SateMenu.MenuItemListener() {   @Override   public void onclick(int position) {    Toast.makeText(MainActivity.this, "-- "+position, Toast.LENGTH_SHORT).show();   }  }); }}

以上所述是小編給大家介紹的Android衛(wèi)星菜單效果的實現(xiàn)方法,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復大家的!


注:相關教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 常宁市| 江油市| 明光市| 石屏县| 大冶市| 土默特右旗| 基隆市| 唐山市| 吴堡县| 屏边| 政和县| 秦皇岛市| 西丰县| 枞阳县| 佛山市| 亚东县| 文水县| 海南省| 宜兰县| 德江县| 石阡县| 花垣县| 张家界市| 万源市| 大兴区| 宝坻区| 日土县| 广水市| 乌拉特中旗| 邻水| 怀来县| 巍山| 株洲市| 衡阳县| 荣成市| 普定县| 互助| 阳春市| 扎赉特旗| 本溪| 叙永县|