Android 自定义组件卫星菜单的实现

卫星菜单 ArcMenu

相信大家接触安卓,从新手到入门的过渡,就应该会了解到卫星菜单、抽屉、Xutils、Coolmenu、一些大神封装好的一些组件。这些组件在 Github 上面很容易搜得到,但是有时候打开会发现看不懂里面的代码,包括一些方法和函数 。。。。。
首先先上效果图:

实现效果

首先如果要想自定义组件

1.那么第一件事就是赋予自定义组件的属性,从效果图上看出,该组件可以存在屏幕的各个角落点,那么位置是其属性之一。

2.既然是卫星菜单,那么主按钮和其附属的小按钮之间的围绕半径也应该作为其参数之一。

3.右图得出,该组件包含很多按钮,主按钮和附属按钮,那么这个组件应该继承 ViewGroup。

一、定义卫星菜单的属性在 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>

二、编写自定义组件

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;
  }

}

以上就是 卫星菜单的编写,上面的注释量比较大。

这里需要注意的一点。卫星菜单在屏幕不同位置,他的动画平移值是不一样的。

如果实在不理解可以画图试试。

三、使用时注意赋予命名空间

<?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>

其他的大家可以自行探索研究。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • Android卫星菜单效果的实现方法

    Android小白第一次写博客,心情无比激动.下面给大家展示一下卫星菜单的实现. 1.简单介绍卫星菜单 在应用程序中,有很多展示菜单的方式,但其功能都是大同小异,这样一来,菜单的美观以及展示方式就显的尤为重要,卫星菜单就是很不错的一种.下面是本案例的gif图: 2.学习本案例需要的知识点 (1)动画 (2)自定义ViewGroup (3)自定义属性 a.attr.xml b.在布局中使用自定义属性 c.在代码中获取自定义属性值 3.首先分析我们的卫星菜单需要那些自定义属性并书写代码 首先,菜单可

  • Android自定义VIew实现卫星菜单效果浅析

     一 概述: 最近一直致力于Android自定义VIew的学习,主要在看<android群英传>,还有CSDN博客鸿洋大神和wing大神的一些文章,写的很详细,自己心血来潮,学着写了个实现了类似卫星效果的一个自定义的View,分享到博客上,望各位指点一二.写的比较粗糙,见谅.(因为是在Linux系统下写的,效果图我直接用手机拍的,难看,大家讲究下就看个效果,勿喷). 先来看个效果图,有点不忍直视: 自定义VIew准备: (1)创建继承自View的类; (2)重写构造函数; (3)定义属性. (

  • Android 自定义组件卫星菜单的实现

    卫星菜单 ArcMenu 相信大家接触安卓,从新手到入门的过渡,就应该会了解到卫星菜单.抽屉.Xutils.Coolmenu.一些大神封装好的一些组件.这些组件在 Github 上面很容易搜得到,但是有时候打开会发现看不懂里面的代码,包括一些方法和函数 ..... 首先先上效果图: 实现效果 首先如果要想自定义组件 1.那么第一件事就是赋予自定义组件的属性,从效果图上看出,该组件可以存在屏幕的各个角落点,那么位置是其属性之一. 2.既然是卫星菜单,那么主按钮和其附属的小按钮之间的围绕半径也应该作

  • Android 自定义组件成JAR包的实现方法

    Android 自定义组件成JAR包的实现方法,这里对自己实现的Android View 组件进行JAR 包的处理. 在项目开发过程中,我们难免会用到自己去制作自定义的VIEW控件,之后我们别的项目如果需要的话就直接将其复制到对应的项目中使用,虽说这么做是一个解决问题的方法,但毕竟不是很好. 原因是,当我们项目积累越来越多,会发现自定义的控件越来越多,而且这些自定义的控件都是可以重复利用的,这时我们可以想想,如果把这些自定义控件都封装成一个JAR包,然后用一个项目积累起来,之后我们以后开发项目只

  • Android 自定义弹出菜单和对话框功能实例代码

    Android 开发当中,可能会存在许多自定义布局的需求,比如自定义弹出菜单(popupWindow),以及自定义对话框(Dialog). 话不多说,直接上图片. 先讲第一种,自定义PopUpWindow 1.popupWindow protected void showPopWindow(View view, final int pos){ WindowManager wm= (WindowManager) myContext.getSystemService(Context.WINDOW_S

  • android自定义组件实现方法

    本文实例讲述了android自定义组件实现方法.分享给大家供大家参考.具体如下: atts.xml: <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="TopBar"> <attr name="titleText" format="string"/> <

  • Android自定义View展开菜单功能的实现

    先给大家展示下效果图,如果大家感觉不错,请参考实现代码. 思路 1.下角Button的父View加入一个FrameLayout,也就是图中全屏透明灰色部分. 菜单没有弹出的时候设置为不可见. 设置FrameLayout点击事件,点击的时候缩回菜单. 对应init() 2.rameLayout中加入菜单按钮,也就是弹出的那三个. 菜单没有弹出的时候设置为不可见. 对应addElement()和freshElement() 3.右下角的按钮,旋转图标(也可以不旋转). 对应setRotateAnim

  • Android自定义横向滑动菜单的实现

    本文讲述了Android自定义横向滑动菜单的实现.分享给大家供大家参考,具体如下: 前言 开发安卓过程中,经常会用到标题栏的样式,有时候传统方式不能满足开发者的需要,这时候就需要自定义控件来实现.(注意:本文提供思路,有关键代码,但是代码不全) 标题栏说明 自定义标题栏ColumnHorizontalScrollView继承HorizontalScrollView 这个安卓原生的控件,HorizontalScrollView是一种FrameLayout(框架布局),其子项被滚动查看时是整体移动的

  • Android自定义实现侧滑菜单效果

    本文实例为大家分享了Android自定义实现侧滑菜单的具体代码,供大家参考,具体内容如下 实现原理:继承ViewGroup控件要显示到界面上需要重写OnMeature() OnLayout(),因此在实现OnLayout()的时候,将菜单界面划出到屏幕左侧,动态改变菜单界面距离scrollXto()左边界的距离就能实现滑动效果. 1.继承ViewGroup 2.事件分发机制 3.状态监听 在主界面中添加两个子控件 <com.oblivion.ui.SlideMenu xmlns:android=

  • Android自定义组件获取本地图片和相机拍照图片

    iOS中有封装好的选择图片后长按出现动画删除效果,效果如下 而Android找了很久都没有找到有这样效果的第三方组件,最后懒得找了还是自己实现这效果吧 选择图片后还可对图片进行剪裁 当然,代码中还有很多不完善的地方,我接下来会继续完善这个组件的 已经上传到开源社区,欢迎大家来Star啊~ Demo源码:传送门 设计中的碰到的一些问题和解决思路 1.如何让加号图片显示在GridView最后面 首先在调用GridAdapter构造方法时就加载加号图片 /** * 图片适配器 * @param con

  • Android自定义ViewGroup(侧滑菜单)详解及简单实例

    自定义侧滑菜单的简单实现 不少APP中都有这种侧滑菜单,例如QQ这类的,比较有名开源库如slidingmenu. 有兴趣的可以去研究研究这个开源库. 这里我们将一种自己的实现方法,把学习的 东西做个记录,O(∩_∩)O! 首先看效果图: 这里我们实现的侧滑菜单,是将左侧隐藏的菜单和主面板看作一个整体来实现的,而左侧隐藏的菜单和主面板相当于是这个自定义View的子View. 首先来构造该自定义View的布局: 自定义的SlideMenuView包含两个子view,一个是menuView,另一个是m

  • Android自定义组件跟随自己手指主动画圆

    本文实例为大家分享了Android实现跟随手指画圆的具体代码,供大家参考,具体内容如下 首先自己定义一个View子类: package com.example.androidtest0.myView; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.Att

随机推荐

其他