Android 사용자 정의 구성 요소 위성 메뉴 구현

18978 단어 Android위성 메뉴
위성 메뉴 ArcMenu
안 드 로 이 드 를 접 하고 초보 자 에서 입문 까지 의 과 도 를 통 해 위성 메뉴,서랍,Xutils,Coolmenu,큰 신 들 이 봉 인 된 구성 요 소 를 알 수 있 을 것 이 라 고 믿 습 니 다.이 구성 요소 들 은 Github 에서 쉽게 찾 을 수 있 지만 가끔 열 면 안에 있 는 코드 를 알 아 볼 수 없습니다.방법 과 함 수 를 포함 합 니 다...
우선 효과 도 를 올 립 니 다:
실현 효과

우선 구성 요 소 를 사용자 정의 하려 면
1.첫 번 째 는 사용자 정의 구성 요소 의 속성 을 부여 하 는 것 입 니 다.효과 그림 에서 보 듯 이 이 구성 요 소 는 화면의 구석구석 에 존재 할 수 있 습 니 다.그러면 위 치 는 그 속성 중 하나 입 니 다.
2.위성 메뉴 인 만큼 메 인 버튼 과 그 부속 버튼 사이 의 반지름 도 그 매개 변수 중 하나 가 되 어야 한다.
3.오른쪽 그림 에서 이 구성 요 소 는 많은 단추,메 인 단추 와 부속 단 추 를 포함 하고 있 습 니 다.그러면 이 구성 요 소 는 View Group 을 계승 해 야 합 니 다.
1.위성 메뉴 의 속성 을 values 패키지 에 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>

  <!--     dp    px           -->
  <attr name="radius" format="dimension" />
  <!--      -->
  <declare-styleable name="ArcMenu">

    <attr name="position" />
    <attr name="radius" />


  </declare-styleable>


</resources>

2.사용자 정의 구성 요소 작성

package com.lanou.dllo.arcmenudemo.arcmenu;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;

import com.lanou.dllo.arcmenudemo.R;

/**
 * Created by dllo on 16/3/25.
 * 1.  ArcMenu   ViewGroup,                       .
 */

public class ArcMenu extends ViewGroup implements View.OnClickListener {

  //    ,     
  private static final int POS_LEFT_TOP = 0;
  private static final int POS_LEFT_BOTTOM = 1;
  private static final int POS_RIGHT_TOP = 2;
  private static final int POS_RIGHT_BOTTOM = 3;

  //  5          .
  //              
  private Position mPosition = Position.RIGHT_BOTTOM;
  private int mRadius;

  /**
   *      
   */
  private Status mCurrentStatus = Status.CLOSE;

  /**
   *       
   */
  private View mCButton;

  //        
  private OnMenuItemClickListener mMenuItemClickListener;


  /**
   *         ,4   
   */
  public enum Position {
    LEFT_TOP, LEFT_BOTTOM, RIGHT_TOP, RIGHT_BOTTOM
  }

  public enum Status {
    OPEN, CLOSE
  }

  /**
   *       ,         
   */
  public interface OnMenuItemClickListener {
    void onClick(View view, int pos);
  }

  //3     ,    .
  //      .
  public ArcMenu(Context context) {
    this(context, null);
  }

  public ArcMenu(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
  }

  public ArcMenu(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    //TypedValue.applyDimension              :       :       :              .
    mRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP
        , 100, getResources().getDisplayMetrics());

    //         
    //  1:attrs AttributeSet        
    //  2:attrs      
    //  3:    theme   item    style  style           TypedArray
    //  4; defStyleAttr       0,         style
    TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
        R.styleable.ArcMenu, defStyleAttr, 0);
    int pos = a.getInt(R.styleable.ArcMenu_position, POS_RIGHT_BOTTOM);
    switch (pos) {
      case POS_LEFT_TOP:
        mPosition = Position.LEFT_TOP;
        break;
      case POS_LEFT_BOTTOM:
        mPosition = Position.LEFT_BOTTOM;
        break;
      case POS_RIGHT_TOP:
        mPosition = Position.RIGHT_TOP;
        break;
      case POS_RIGHT_BOTTOM:
        mPosition = Position.RIGHT_BOTTOM;
        break;
    }

    mRadius = (int) a.getDimension(R.styleable.ArcMenu_radius,
        TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP
            , 100, getResources().getDisplayMetrics()));

    Log.d("TAG", "Position = " + mPosition + ", radius" + mRadius);
    //       .
    a.recycle();

  }

  public void setOnMenuItemClickListener(OnMenuItemClickListener mMenuItemClickListener) {
    this.mMenuItemClickListener = mMenuItemClickListener;
  }

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

  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    if (changed) {
      layoutCButton();
      //          ,          (   )
      int count = getChildCount();
      for (int i = 0; i < count - 1; i++) {
        //         ,   getChildAt(0)      .
        View child = getChildAt(i + 1);
        //    ,        ,     ,      ,              .        ,        .
        child.setVisibility(View.GONE);
        /**
         *       ,             a = 90°/(     -1)
         *   menu   4,      menu1    (0,R);
         * menu2    (R*sin(a),R*cos(a));
         * menu3    (R*sin(2a),R*cos(2a));
         * ...
         * menuN    (R,0);
         *  :PI π
         * */
        //                    
        //  count-2,   count      
        //        (cl,ct);
        int cl = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * i));
        int ct = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2) * i));

        int cWidth = child.getMeasuredWidth();
        int cHeight = child.getMeasuredHeight();

        //           ,           ,     .
        /**
         *              ,  .       
         * */
        if (mPosition == Position.LEFT_BOTTOM || mPosition == Position.RIGHT_BOTTOM) {
          ct = getMeasuredHeight() - cHeight - ct;
        }

        /**
         *   ,  
         * */
        if (mPosition == Position.RIGHT_TOP || mPosition == Position.RIGHT_BOTTOM) {
          cl = getMeasuredWidth() - cWidth - cl;
        }


        //        ;
        child.layout(cl, ct, cl + cWidth, ct + cHeight);


      }
    }

  }

  /**
   *        
   */
  private void layoutCButton() {
    //         
    mCButton = getChildAt(0);
    mCButton.setOnClickListener(this);

    //                 
    int l = 0;
    int t = 0;
    int width = mCButton.getMeasuredWidth();
    int height = mCButton.getMeasuredHeight();

    /**
     * getMeasuredHeight()          ,        ViewGroup,              .
     * getMeasuredWidth()    .
     *                (       .)
     * */
    switch (mPosition) {
      case LEFT_TOP:
        l = 0;
        t = 0;
        break;
      case LEFT_BOTTOM:
        l = 0;
        t = getMeasuredHeight() - height;
        break;
      case RIGHT_TOP:
        l = getMeasuredWidth() - width;
        t = 0;
        break;
      case RIGHT_BOTTOM:
        l = getMeasuredWidth() - width;
        t = getMeasuredHeight() - height;
        break;
    }

    //layout     .                     
    mCButton.layout(l, t, l + width, t + height);

  }


  @Override
  public void onClick(View v) {
    //    mCButton  
    mCButton = findViewById(R.id.id_button);
    if (mCButton == null) {
      mCButton = getChildAt(0);
    }

    //    
    rotateCButton(v, 0f, 360f, 300);
    //        ,             ,               .
    toggleMenu(500);
  }

  /**
   *     
   *   :           .
   */
  public void toggleMenu(int duration) {
    //          . :         
    int count = getChildCount();
    for (int i = 0; i < count - 1; i++) {
      /**
       *         ,         (-cl,-ct);
       *         ,         (+cl,-ct);
       *         ,         (-cl,+ct);
       *         ,         (+cl,+ct);**
       * */
      final View childView = getChildAt(i + 1);
      //         ,               .
      childView.setVisibility(View.VISIBLE);
      //        0,0(          ,    .)
      int cl = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * i));
      int ct = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2) * i));

      //        ,      .
      int xflag = 1;
      int yflag = 1;
      if (mPosition == Position.LEFT_TOP
          || mPosition == Position.LEFT_BOTTOM) {
        xflag = -1;
      }
      if (mPosition == Position.LEFT_TOP
          || mPosition == Position.RIGHT_TOP) {
        yflag = -1;
      }
      //          ,  AnimationSet
      AnimationSet animset = new AnimationSet(true);
      Animation tranAnim = null;

      //to open       
      if (mCurrentStatus == Status.CLOSE) {
        tranAnim = new TranslateAnimation(xflag * cl, 0, yflag * ct, 0);
        //          ,         .
        childView.setClickable(true);
        childView.setFocusable(true);

      } else {//to close
        tranAnim = new TranslateAnimation(0, xflag * cl, 0, yflag * ct);
        //          ,         .
        childView.setClickable(false);
        childView.setFocusable(false);
      }
      tranAnim.setFillAfter(true);
      tranAnim.setDuration(duration);
      //      .
      tranAnim.setStartOffset((i * 100) / count);
      //                ,        ,             .
      tranAnim.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        //      ,    .
        @Override
        public void onAnimationEnd(Animation animation) {
          if (mCurrentStatus == Status.CLOSE) {
//            Log.d("      ",mCurrentStatus +"");
            childView.setVisibility(View.GONE);
          }
        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
      });

      //      (   )
      RotateAnimation rotateAnim = new RotateAnimation(0, 720,
          Animation.RELATIVE_TO_SELF, 0.5f,
          Animation.RELATIVE_TO_SELF, 0.5f);
      rotateAnim.setDuration(duration);
      rotateAnim.setFillAfter(true);

      //            
      //      .     /     ./
      animset.addAnimation(rotateAnim);
      animset.addAnimation(tranAnim);
      childView.startAnimation(animset);

      final int pos = i + 1;
      //          
      childView.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
          if (mMenuItemClickListener != null) {
            mMenuItemClickListener.onClick(childView, pos);
          }
            menuItemAnim(pos - 1);
            //      
            changeStatus();
        }
      });
    }
    /**
     *            ,             .
     *   changeStatus()       ,
     * */
    //      
    changeStatus();

  }


  /**
   *       
   */
  private void changeStatus() {
    //         ,                  .
    mCurrentStatus = (mCurrentStatus == Status.CLOSE ? Status.OPEN :
        Status.CLOSE);
    Log.d("      ", mCurrentStatus + "");
  }

  public boolean isOpen(){
    return mCurrentStatus ==Status.OPEN;
  }




  //                     300
  private void rotateCButton(View v, float start, float end, int duration) {
    RotateAnimation anim = new RotateAnimation(start, end, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    anim.setDuration(duration);
    //          .
    anim.setFillAfter(true);
    v.startAnimation(anim);
  }

  /**
   *   menuItem     
   * */
  private void menuItemAnim(int pos) {
    for (int i = 0; i < getChildCount() - 1; i++) {
      View childView = getChildAt(i + 1);
      //      ,    
      //            ,        
      //          .
      if (i == pos) {
        childView.startAnimation(scaleBigAnim(300));
      } else {
        childView.startAnimation(scaleSmallAnim(300));
      }

      //         ,                      ,
      childView.setClickable(false);
      childView.setFocusable(false);
    }
  }

  /**
   *       Item             
   *
   * @param duration
   * @return
   */
  private Animation scaleBigAnim(int duration) {
    AnimationSet animationSet = new AnimationSet(true);
    ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 4.0f, 1.0f, 4.0f,
        Animation.RELATIVE_TO_SELF, 0.5f,
        Animation.RELATIVE_TO_SELF, 0.5f);
    AlphaAnimation alphaAnimation=new AlphaAnimation(1f,0.0f);

    animationSet.addAnimation(scaleAnimation);
    animationSet.addAnimation(alphaAnimation);

    animationSet.setDuration(duration);
    animationSet.setFillAfter(true);
    return animationSet;
  }

  private Animation scaleSmallAnim(int duration) {
    AnimationSet animationSet = new AnimationSet(true);
    ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 0.0f, 1.0f, 0.0f,
        Animation.RELATIVE_TO_SELF, 0.5f,
        Animation.RELATIVE_TO_SELF, 0.5f);
    AlphaAnimation alphaAnimation=new AlphaAnimation(1f,0.0f);
    animationSet.addAnimation(scaleAnimation);
    animationSet.addAnimation(alphaAnimation);
    animationSet.setDuration(duration);
    animationSet.setFillAfter(true);
    return animationSet;
  }

}

이상 은 위성 메뉴 의 작성 입 니 다.위의 주석 은 비교적 많 습 니 다.
여기 서 주의해 야 할 점.위성 메뉴 는 화면 이 다른 위치 에 있 고 그의 애니메이션 이동 값 은 다르다.
이해 가 안 되면 그림 을 그 려 보 세 요.
3.사용 시 네 임 스페이스 부여

<?xml version="1.0" encoding="utf-8"?>
<com.lanou.dllo.arcmenudemo.arcmenu.ArcMenu xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:arcmenu="http://schemas.android.com/apk/res/com.lanou.dllo.arcmenudemo"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/id_menu"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  arcmenu:position="left_top"
  arcmenu:radius="140dp"
>


    <!--    -->
    <RelativeLayout
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:background="@mipmap/composer_button">

      <ImageView
        android:id="@+id/id_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:src="@mipmap/composer_icn_plus" />
    </RelativeLayout>


    <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@mipmap/composer_camera"
      android:tag="Camera"/>

    <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@mipmap/composer_music"
      android:tag="Music"/>

    <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@mipmap/composer_place"
      android:tag="Place"/>

    <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@mipmap/composer_sleep"
      android:tag="Sleep"/>

    <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@mipmap/composer_thought"
      android:tag="Sun"/>

    <ImageView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@mipmap/composer_with"
      android:tag="People"/>

</com.lanou.dllo.arcmenudemo.arcmenu.ArcMenu>

다른 사람들 은 스스로 탐색 하고 연구 할 수 있다.
읽 어 주 셔 서 감사합니다. 여러분 에 게 도움 이 되 기 를 바 랍 니 다.본 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기