热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

CreatingCustomViews自定义View

虽然Android为我们提供了很多的内置控件,但是有时候我们的独特的业务需求可能这些内置控件仍然无法满足,那么此时,就需要我们自定义控件。这系列文章将向你展示如何创建一个功能强大且

虽然Android为我们提供了很多的内置控件,但是有时候我们的独特的业务需求可能这些内置控件仍然无法满足,那么此时,就需要我们自定义控件。这系列文章将向你展示如何创建一个功能强大且可重复的View控件。

目录:

  • 创建自定义View Class Creating a View Class
  • 自定义绘图 Custom Drawing
  • 控件交互 Making the View Interactive
  • 优化View控件 Optimizing the View

自定义View

一个良好的自定义View应该能和Android内置的View控件一样,具有良好的表现:具有自己的属性能与用户进行交互占据有效的内存空间。因此一个自定义的View的Class应该具备以下几个特征:

  1. 继承自View或者是View的子类,在Android中所有的View控件比如:Button,TextView都是View的子类。
  2. 符合Android的标准
  3. 通过xml文件提供自定义的属性
  4. 能与用户交互,能够响应事件,传递事件
  5. 兼容Android多个平台和版本

有了以上的标准,那么接下来就学习如何构造一个功能完整的自定义View吧:
大体上分为以下若干步骤:

  • 继承一个View或者View子类
  • 在res/values/attrs.xml文件中自定义属性
  • 应用我们的自定义属性
  • 添加属性和事件
  • 供外界调用
  1. 在Android的所有View体系中,所有的控件都是继承自View的,所以我们自定义控件的时候也应该是继承View或者是View的子类,比如Button,TextView。需要注意的是:大部分时候,我们自定义View是为了想在布局文件中xml调用,此时,我们的自定义View需要覆盖如下的构造方法来能在xml中被实例化,否则会报错。

    class PieChart extends View {
    public PieChart(Context context, AttributeSet attrs) {//必须有此构造函数才能在xml文件中被实例化
    super(context, attrs); //调用父类的构造函数
    }
    }

    另外,我们之所以自定义View大多数是因为想实现业务需求的View,此时基本是需要在重写onDraw()方法来绘制我们的View。

    @Override
    protected void onDraw(Canvas canvas) { //自定义View中都会重写此onDraw()方法
    super.onDraw(canvas); //调用父类的onDraw();
    // Draw the shadow
    canvas.drawOval(mShadowBounds, mShadowPaint);

// Draw the label text
if (getShowText()) {
canvas.drawText(mData.get(mCurrentItem).mLabel, mTextX, mTextY, mTextPaint);
}
// If the API level is less than 11, we can’t rely on the view animation system to
// do the scrolling animation. Need to tick it here and call postInvalidate() until the scrolling is done.
if (Build.VERSION.SDK_INT <11) {
tickScrollAnimation();
if (!mScroller.isFinished()) {
postInvalidate();
}
}
}

  1. 自定义属性
    自定义属性后就能像Android内置的View控件一样通过属性标签来控制,我们自定义属性的时候需要在res/values/attrs.xml文件下以为根标签属性名和类型以键值对的方式存储。






        
       




    需要注意的地方是:我们在布局文件中使用自定义属性的时候需要加上命名空间,命名空间可以加在根标签也可以加在自定义View标签内,一般直接加在根标签里。命名空间的格式如下:
    http://schemas.android.com/apk/res/[yourpackagename],比如:
    xmlns:custom=&#8221;http://schemas.android.com/apk/res/com.example.android.customviews&#8220;
    还有特殊的情况:在你自定义的View中有一个内部的自定义innerView,如果希望在xml文件中使用innerView的属性,比如PieChart内有个PieView的内部类,那么应该这样:
    com.example.customviews.charting.PieChart$PieView。在xml引用自定义View布局需要使用全名,代码如下:


    xmlns:android=&#8221;http://schemas.android.com/apk/res/android&#8220;
    xmlns:custom=&#8221;http://schemas.android.com/apk/res/com.example.customviews&#8220;> //自定义属性命名空间
    custom:showText=&#8221;true&#8221;
    custom:labelPosition=&#8221;left&#8221;
    />

  2. 在代码中应用我们自定义的属性,使xml中的属性能够产生效果
    当一个view从xml布局中创建后,其使用的所有属性都会读取并传递到view 构造器函数的AttributeSet中。但是倘若直接使用AttributeSet会有一些缺点比如:styles不能生效,引用的资源不能解析。这时,我们使用另外一种方法会好很多,使用[obtainStyledAttributes()](http://developer.android.com/reference/android/content/res/Resources.Theme.html#obtainStyledAttributes(android.util.AttributeSet, int[], int, int))将在xml定义的属性封装到 TypedArray中去。代码如下:


    public PieChart(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.PieChart, 0, 0);
    try {
    mShowText = a.getBoolean(R.styleable.PieChart_showText, false);
    mTextPos = a.getInteger(R.styleable.PieChart_labelPosition, 0);
    } finally {
    a.recycle(); //释放资源
    }
    }

  3. 添加属性事件
    添加属性事件暴露方法,使view可以动态改变


    public boolean isShowText() {
    return mShowText;
    }
    public void setShowText(boolean showText) {
    mShowText = showText;
    invalidate();//重绘
    requestLayout();
    }

    注意:invalidate()和requestLayout
    requestLayout:当view确定自身已经不再适合现有的区域时,该view本身调用这个方法要求parent view重新调用他的onMeasure onLayout来对重新设置自己位置。
    特别的当view的layoutparameter发生改变,并且它的值还没能应用到view上,这时候适合调用这个方法。invalidate:View本身调用迫使view重画。
    另外:一个好的自定义View应该暴露接口,提供对业务有用的部分监听机制供自己调用。比如:OnCurrentItemChanged(),onColorChanged(),onSizeChanged().

小结:

  • 对于自定义View需要注意的大概就是这些,但是在实际自己写的时候仍然会有很多的问题,需要多实践,多学习别人的代码,再结合自己的业务区自定义。当然如果有第三方的控件可以满足我们的业务需求,我们亦可以引用。

Google给出的一个完整的自定义view的例子:点击下载Customview.zip


推荐阅读
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文介绍了一款名为TimeSelector的Android日期时间选择器,采用了Material Design风格,可以在Android Studio中通过gradle添加依赖来使用,也可以在Eclipse中下载源码使用。文章详细介绍了TimeSelector的构造方法和参数说明,以及如何使用回调函数来处理选取时间后的操作。同时还提供了示例代码和可选的起始时间和结束时间设置。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 如何在HTML中获取鼠标的当前位置
    本文介绍了在HTML中获取鼠标当前位置的三种方法,分别是相对于屏幕的位置、相对于窗口的位置以及考虑了页面滚动因素的位置。通过这些方法可以准确获取鼠标的坐标信息。 ... [详细]
  • 本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ... [详细]
  • 本文总结了在编写JS代码时,不同浏览器间的兼容性差异,并提供了相应的解决方法。其中包括阻止默认事件的代码示例和猎取兄弟节点的函数。这些方法可以帮助开发者在不同浏览器上实现一致的功能。 ... [详细]
  • 展开全部下面的代码是创建一个立方体Thisexamplescreatesanddisplaysasimplebox.#Thefirstlineloadstheinit_disp ... [详细]
  • C# WPF自定义按钮的方法
    本文介绍了在C# WPF中实现自定义按钮的方法,包括使用图片作为按钮背景、自定义鼠标进入效果、自定义按压效果和自定义禁用效果。通过创建CustomButton.cs类和ButtonStyles.xaml资源文件,设计按钮的Style并添加所需的依赖属性,可以实现自定义按钮的效果。示例代码在ButtonStyles.xaml中给出。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • iOS Swift中如何实现自动登录?
    本文介绍了在iOS Swift中如何实现自动登录的方法,包括使用故事板、SWRevealViewController等技术,以及解决用户注销后重新登录自动跳转到主页的问题。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
author-avatar
fjkfjaslfjsal_577
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有