• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Android > Adapter模式实战-重构鸿洋的Android建行圆形菜单

Adapter模式实战-重构鸿洋的Android建行圆形菜单

作者:网友 字体:[增加 减小] 来源:互联网 时间:2017-05-26

网友通过本文主要向大家介绍了鸿洋adapter,adapter,adapter是什么意思,arrayadapter,baseadapter等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

Adapter模式实战-重构鸿洋的Android建行圆形菜单


对于很多开发人员来说,炫酷的UI效果是最吸引他们注意力的,很多人也因为这些炫酷的效果而去学习一些比较知名的UI库。而做出炫酷效果的前提是你必须对自定义View有所理解,作为90的小民自然也不例外。特别对于刚处在开发初期的小民,对于自定义View这件事觉得又神秘又帅气,于是小民决定深入研究自定义View以及相关的知识点。

在此之前我们先来看看洋神的原版效果图:

\

记得那是2014年的第一场雪,比以往时候来得稍晚一些。小民的同事洋叔是一位资深的研发人员,擅长写UI特效,在开发领域知名度颇高。最近洋叔刚发布了一个效果不错的圆形菜单,这个菜单的每个Item环形排布,并且可以转动。小民决定仿照洋叔的效果实现一遍,但是对于小民这个阶段来说只要实现环形布局就不错了,转动部分作为下个版本功能,就当作自定义View的练习了。

在google了自定义View相关的知识点之后,小民就写好了这个圆形菜单布局视图,我们一步一步来讲解,代码如下:

// 圆形菜单
public class CircleMenuLayout extends ViewGroup {
    // 圆形直径
    private int mRadius;
    // 该容器内child item的默认尺寸
    private static final float RADIO_DEFAULT_CHILD_DIMENSION = 1 / 4f;
    // 该容器的内边距,无视padding属性,如需边距请用该变量
    private static final float RADIO_PADDING_LAYOUT = 1 / 12f;
    // 该容器的内边距,无视padding属性,如需边距请用该变量
    private float mPadding;
    // 布局时的开始角度
    private double mStartAngle = 0;
    // 菜单项的文本
    private String[] mItemTexts;
    // 菜单项的图标
    private int[] mItemImgs;
    // 菜单的个数
    private int mMenuItemCount;
    // 菜单布局资源id
    private int mMenuItemLayoutId = R.layout.circle_menu_item;
    // MenuItem的点击事件接口
    private OnItemClickListener mOnMenuItemClickListener;

    public CircleMenuLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 无视padding
        setPadding(0, 0, 0, 0);
    }

    // 设置菜单条目的图标和文本
    public void setMenuItemIconsAndTexts(int[] images, String[] texts) {
        if (images == null && texts == null) {
            throw new IllegalArgumentException("菜单项文本和图片至少设置其一");
        }

        mItemImgs = images;
        mItemTexts = texts;
        // 初始化mMenuCount
        mMenuItemCount = images == null ? texts.length : images.length;
        if (images != null && texts != null) {
            mMenuItemCount = Math.min(images.length, texts.length);
        }
        // 构建菜单项
        buildMenuItems();
    }

    // 构建菜单项
    private void buildMenuItems() {
        // 根据用户设置的参数,初始化menu item
        for (int i = 0; i < mMenuItemCount; i++) {
            View itemView = inflateMenuView(i);
            // 初始化菜单项
            initMenuItem(itemView, i);
            // 添加view到容器中
            addView(itemView);
        }
    }

    private View inflateMenuView(final int childIndex) {
        LayoutInflater mInflater = LayoutInflater.from(getContext());
        View itemView = mInflater.inflate(mMenuItemLayoutId, this, false);
        itemView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mOnMenuItemClickListener != null) {
                    mOnMenuItemClickListener.onClick(v, childIndex);
                }
            }
        });
        return itemView;
    }

    private void initMenuItem(View itemView, int childIndex) {
        ImageView iv = (ImageView) itemView
                .findViewById(R.id.id_circle_menu_item_image);
        TextView tv = (TextView) itemView
                .findViewById(R.id.id_circle_menu_item_text);
        iv.setVisibility(View.VISIBLE);
        iv.setImageResource(mItemImgs[childIndex]);
        tv.setVisibility(View.VISIBLE);
        tv.setText(mItemTexts[childIndex]);
    }

    // 设置MenuItem的布局文件,必须在setMenuItemIconsAndTexts之前调用
    public void setMenuItemLayoutId(int mMenuItemLayoutId) {
        this.mMenuItemLayoutId = mMenuItemLayoutId;
    }

    // 设置MenuItem的点击事件接口
    public void setOnItemClickListener(OnItemClickListener listener) {
        this.mOnMenuItemClickListener = listener;
    }
    // 代码省略
}

小民的思路大致是这样的,首先让用户通过setMenuItemIconsAndTexts函数将菜单项的图标和文本传递进来,根据这些图标和文本构建菜单项,菜单项的布局视图由mMenuItemLayoutId存储起来,这个mMenuItemLayoutId默认为circle_menu_item.xml,这个xml布局为一个ImageView显示在一个文本控件的上面。为了菜单项的可定制型,小民还添加了一个setMenuItemLayoutId函数让用户可以设置菜单项的布局,希望用户可以定制各种各样的菜单样式。在用户设置了菜单项的相关数据之后,小民会根据用户设置进来的图标和文本数量来构建、初始化相等数量的菜单项,并且将这些菜单项添加到圆形菜单CircleMenuLayout中。然后添加了一个可以设置用户点击菜单项的处理接口的setOnItemClickListener函数,使得菜单的点击事件可以被用户自定义处理。

在将菜单项添加到CircleMenuLayout之后就是要对这些菜单项进行尺寸丈量和布局了,我们先来看丈量尺寸的代码,如下 :

    //设置布局的宽高,并策略menu item宽高
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 丈量自身尺寸
        measureMyself(widthMeasureSpec, heightMeasureSpec);
        // 丈量菜单项尺寸
        measureChildViews();
    }

    private void measureMyself(int widthMeasureSpec, int heightMeasureSpec) {
        int resWidth = 0;
        int resHeight = 0;
        // 根据传入的参数,分别获取测量模式和测量值
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        // 如果宽或者高的测量模式非精确值
        if (widthMode != MeasureSpec.EXACTLY
                || heightMode != MeasureSpec.EXACTLY) {
            // 主要设置为背景图的高度
            resWidth = getSuggestedMinimumWidth();
            // 如果未设置背景图片,则设置为屏幕宽高的默认值
            resWidth = resWidth == 0 ? getDefaultWidth() : resWidth;
            resHeight = getSuggestedMinimumHeight();
            // 如果未设置背景图片,则设置为屏幕宽高的默认值
            resHeight = resHeight == 0 ? getDefaultWidth() : resHeight;
        } else {
            // 如果都设置为精确值,则直接取小值;
            resWidth = resHeight = Math.min(width, height);
        }
        setMeasuredDimension(resWidth, resHeight);
    }

    private void measureChildViews() {
        // 获得半径
        mRadius = Math.max(getMeasuredWidth(), getMeasuredHeight());
        // menu item数量
        final int count = getChildCount();
        // menu item尺寸
        int childSize = (int) (mRadius * RADIO_DEFAULT_CHILD_DIMENSION);
        // menu item测量模式
        int childMode = MeasureSpec.EXACTLY;
        // 迭代测量
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() == GONE) {
                continue;
            }
            // 计算menu item的尺寸;以及和设置好的模式,去对item进行测量
            int makeMeasureSpec = -1;
            makeMeasureSpec = MeasureSpec.makeMeasureSpec(childSize,
                    childMode);
            child.measure(makeMeasureSpec, makeMeasureSpec);
        }
        mPadding = RADIO_PADDING_LAYOUT * mRadius;
    }

代码比较简单,就是先测量CircleMenuLayout的尺寸,然后测量每个菜单项的尺寸。尺寸获取了之后就到了布局这一步,这也是整个圆形菜单的核心所在。代码如下 :

    // 布局menu item的位置
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int childCount = getChildCount();
        int left, top;
        // menu item 的尺寸
        int itemWidth = (int) (mRadius * RADIO_DEFAULT_CHILD_



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • Adapter模式实战-重构鸿洋的Android建行圆形菜单

相关文章

  • 2017-05-26Android音乐播放器源码(歌词.均衡器.收藏.qq5.0菜单.通知),android.qq5.0
  • 2017-05-26应用开始界面简单倒计时的dialog,界面倒计时dialog
  • 2017-05-26android6.0的坑,android6.0
  • 2017-05-26Android studio Error occurred during initialization of VM 问题解决,initializationofvm
  • 2017-05-26android fragment生命周期应用
  • 2017-05-26fastdfs 使用遇到的问题
  • 2017-05-26Couldn&#39;t load libPassword from loader:NDK开发中C文件编译成cpu的so类库时,找不到类库报错的原因之一,libpasswordndk
  • 2017-05-26View控件中android:drawablePadding不起作用的原因探究,
  • 2017-05-26Android反编译和二次打包实战
  • 2017-05-26使用Android studio创建的AIDL编译时找不到自定义类的解决办法,androidaidl

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • Android开发学习——SQLite数据库与单元测试,androidsqlite
    • Android学习笔记(27):日历视图Calendar浅析
    • 2.4.2 Date & Time组件(上)
    • 我的Android第五章:通过Intent实现活动与活动之间的交互,androidintent
    • ListView添加头布局和脚布局,listview添加布局
    • Cheatsheet: 2017 04.01 ~ 04.30,cheatsheet04.30
    • kvm性能优化
    • Android 手机卫士--导航界面1的布局编写,android卫士
    • 安卓开源项目周报1214,安卓开源项目1214
    • Android的Message Pool是什么——源码角度分析,androidpool

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有