文档章节

Android自定义控件View的探讨

谁带我去看看世界
 谁带我去看看世界
发布于 2015/06/24 15:31
字数 2890
阅读 677
收藏 18
点赞 0
评论 0

本文转载自:http://www.apkbus.com/forum.php?mod=viewthread&tid=242501&extra=page%3D1



做过了一段时间的安卓开发都会接触到自定义控件,那么对于自定义控件大家都有什么样的看法呢?自定义控件他的优势是明显的,设计他的思想又有哪些呢?会用到什么模式呢?希望大家看了这个文章之后,可以发表自己对于自定义控件的看法和思想,这个帖就是为了跟大家交流而发。下面是我自己的一些看法,大侠们请指导!!!


自定义View:

在这里我们先来了解自定义控件view所需要的一些基础知识,以及常见做法。


自定义View类的构造方法

创建自定义控件的3种主要实现方式:


1)继承已有的控件来实现自定义控件

主要是当要实现的控件和已有的控件在很多方面比较类似, 通过对已有控件的扩展来满足要求。


2)通过继承一个布局文件实现自定义控件

一般来说做组合控件时可以通过这个方式来实现。

注意此时不用onDraw方法,在构造函数中通过inflater加载自定义控件的布局文件,再addView(view),自定义控件的图形界面就加载进来了。

例如:

假设我已经有了一个布局的XML文件,里面有一个textview和一个imageview,那么在自定义view的构造方法里这样写就可以使用刚刚的布局XML啦。


public MyView(Context context, AttributeSet attrs) {

super(context, attrs);

// TODO Auto-generated constructor stub

LayoutInflater inflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

inflater.inflate(R.layout.myView, this);

imageView=(ImageView) findViewById(R.id.imageView1);

textView=(TextView)findViewById(R.id.textView1);

}



3)通过继承view类来实现自定义控件,使用GDI绘制出组件界面,一般无法通过上述两种方式来实现时用该方式。




自定义View增加属性的两种方法


1)在View类中定义。通过构造函数中引入的AttributeSet 去查找XML布局的属性名称,然后找到它对应引用的资源ID去找值。


在下面自定义了两个属性Text, Src。

布局文件:


<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical" >



<com.apkbus.MyView

android:id="@+id/myView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

Text="@string/hello_world"

Src="@drawable/logo"/>



</LinearLayout>


属性Text, Src在自定义View类的构造方法中读取。

Java代码:


public MyView(Context context, AttributeSet attrs) {

super(context, attrs);

int resourceId = 0;

int textId = attrs.getAttributeResourceValue(null, "Text",0);

int srcId = attrs.getAttributeResourceValue(null, "Src", 0);

mtext = context.getResources().getText(textId).toString();



}


2)通过XMLView注册属性。与Android提供的标准属性写法一样。

例如:

需要自定义属性Text,SelectSrc,先创建attrs.xml进行属性声明, 文件放在values目录下。


<?xml version="1.0" encoding="utf-8"?>

<resources>



<declare-styleable name="MyView">

<attr name="Text" format="reference|string"></attr>

<attr name="Select" >

<enum name="open" value="1"></enum>

<enum name="close" value="0"></enum>

</attr>

<attr name="Src" format="reference|integer"></attr>

</declare-styleable>



</resources>


在布局中使用这个自定义属性:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:myView="http://schemas.android.com/apk/res/com.apkbus.myview"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

>



<com.apkbus.MyView

android:id="@+id/myView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

myView:Text="www.apkbug.com"

myView:Src="@drawable/img"

myView:Select="open">

</com.apkbus.MyView>



</LinearLayout>



说明:


在使用自定义布局的时候需要添加这样的一行在布局的开头位置

xmlns:myView="http://schemas.android.com/apk/res/com.apkbus.myview"


1、myView是自定义的一个命名空间,你可以取一个喜欢的名称。



2、"http://schemas.android.com/apk/res/com.apkbus.myview"这部分的字符串是由”http://schemas.android.com/apk/res/”和应用的包名”com.apkbus.myview”组成。




然后在自定义View类的构造方法中读取


public MyView(Context context, AttributeSet attrs) {

super(context, attrs);

String pkName = "http://schemas.android.com/apk/res/" + context.getPackageName();

int textId = attrs.getAttributeResourceValue(pkName , "Text",0);

int srcId = attrs.getAttributeResourceValue(pkName , "Src", 0);

int select = attrs.getAttributeIntValue(pkName, "select", 0);

mtext = context.getResources().getText(textId).toString();



}



自定义View的常用方法

onFinishInflate() 回调方法,当应用从XML加载该组件并用它构建界面之后调用的方法


onMeasure() 检测View组件及其子组件的大小


onLayout() 当该组件需要分配其子组件的位置、大小时


onSizeChange() 当该组件的大小被改变时


onDraw() 当组件将要绘制它的内容时


onKeyDown 当按下某个键盘时


onKeyUp  当松开某个键盘时


onTrackballEvent 当发生轨迹球事件时


onTouchEvent 当发生触屏事件时


onWindowFocusChanged(boolean)  当该组件得到、失去焦点时


onAtrrachedToWindow() 当把该组件放入到某个窗口时


onDetachedFromWindow() 当把该组件从某个窗口上分离时触发的方法


onWindowVisibilityChanged(int): 当包含该组件的窗口的可见性发生改变时触发的方法





View的设计理念:

看到这个小标题可能感觉好高端,都到了理念的层次了。其实跟“View的设计目的”这个标题是差不多意思的。

做了开发这么久了,我总结了大概这几个设计的目的。


1、重用性目的

为了可以在不同的模块、项目中重复使用而设计。



2、灵活性目的

自定义View可以方便的实现系统提供的控件所没有的功能,开发项目的时候灵活性大大增加。



3、解耦合目的

由于自定义控件是相对独立的,自然其与其他模块之间的耦合性也是比较低的。模块间解耦自然就不可或缺咯。



既然有了目的,那么怎么实现就成为以下命题了,在这里我想跟你们谈谈设计模式。

在前面大家已经了解了实现一个自定义View的基本方法,但是做起来估计也是蹑手蹑脚的,不知道该如何具体的实现,我把这种迷惘叫缺少指导思想。


这里的指导思想就是设计模式,业务逻辑代码应该放哪?UI代码应该放哪?数据存储代码又应该放哪?只有明确了上面三个问题才算是达到了自定义View的设计目的。






用在View设计的模式:


用在View上的设计模式是很多的,下面列举一些比较常用的模式供大家了解学习。


1、设配器模式




对于android开发者来说起,适配器模式简直太熟悉不过,有很多应用可以说是天天在直接或者间接的用到适配器模式,比如ListView。

ListView用于显示列表数据,但是作为列表数据集合有很多形式,有Array,有Cursor,我们需要对应的适配器作为桥梁,处理相应的数据(并能形成ListView所需要的视图)。

正是因为定义了这些适配器接口和适配器类,才能使我们的数据简单灵活而又正确的显示到了adapterview的实现类上。


目的:

适配器模式,把一个类的接口变换成客户端所期待的另一种接口,从而使原本不匹配而无法在一起工作的两个类能够在一起工作。

适配器模式分为类适配器模式和对象适配器模式。

关于类适配器模式,因为java的单继承,如果继承一个类,另外的则只能是接口,需要手动实现相应的方法。



2、组合模式


Android中对组合模式的应用,可谓是泛滥成粥,随处可见,那就是View和ViewGroup类的使用。在android UI设计,几乎所有的widget和布局类都依靠这两个类。

组合模式,Composite Pattern,是一个非常巧妙的模式。几乎所有的面向对象系统都应用到了组合模式。


目的:

将对象View和ViewGroup组合成树形结构以表示"部分-整体"的层次结构(View可以做为ViewGroup的一部分)。

组合模式使得用户对单个对象View和组合对象ViewGroup的使用具有一致性。


3、MVC模式




MVC是三个单词的缩写,分别为: 模型(Model),视图(View)和控制Controller)。 MVC模式的目的就是实现Web系统的职能分工。 Model层实现系统中的业务逻辑。 View层用于与用户的交互。 Controller层是Model与View之间沟通的桥梁,它可以分派用户的请求并选择恰当的视图以用于显示,同时它也可以解释用户的输入并将它们映射为模型层可执行的操作。



1) 视图层(View):一般采用XML文件进行界面的描述,使用的时候可以非常方便的引入。当然,如何你对Android了解的比较的多了话,就一定可以想到在Android中也可以使用JavaScript+HTML等的方式作为View层,当然这里需要进行Java和JavaScript之间的通信,幸运的是,Android提供了它们之间非常方便的通信实现。     


2) 控制层(Controller):Android的控制层的重任通常落在了众多的Acitvity的肩上,这句话也就暗含了不要在Acitivity中写代码,要通过Activity交割Model业务逻辑层处理,这样做的另外一个原因是Android中的Acitivity的响应时间是5s,如果耗时的操作放在这里,程序就很容易被回收掉。



3) 模型层(Model):对数据库的操作、对网络等的操作都应该在Model里面处理,当然对业务计算等操作也是必须放在的该层的。就是应用程序中二进制的数据。


4、MVP模式



MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller。



在MVP模式里通常包含4个要素:


(1)View:负责绘制UI元素、与用户进行交互(在Android中体现为Activity);



(2)View interface:需要View实现的接口,View通过View interface与Presenter进行交互,降低耦合,方便进行单元测试;



(3)Model:负责存储、检索、操纵数据(有时也实现一个Model interface用来降低耦合);



(4)Presenter:作为View与Model交互的中间纽带,处理与用户交互的负责逻辑。



核心思想:

看了这么多模式,看到头都晕了,我都没耐性看咯。好啦,我来解说一下吧!


其实这么多的模式都有这样的一个核心思想,了解了这个思想之后这些模式不过是同一个思想的不同实现罢了。



1、物理分离

将处理业务逻辑、UI布局、数据存储的代码进行物理分离,分别放在不同的文件中。



2、外部调用

不同的层之间交互一定是通过调用层的开放方法来实现,比如逻辑层不会调用UI层(view类)的父类方法,而是调用其自定义方法。



3、低耦合




最后:



最后,希望大家广开金口,聊聊自己对自定义view的见解,或者对模式的理解。希望大家可以分享,如果文章有错也希望可以指正。

© 著作权归作者所有

共有 人打赏支持
谁带我去看看世界
粉丝 11
博文 11
码字总数 12762
作品 0
广州
Android 自定义组合控件小结

引言 接触Android UI开发的这段时间以来,对自定义组合控件有了一定的了解,为此小结一下,本文小结内容主要讨论的是如何使用Android SDK提供的布局和控件组成一个功能完整组合控件并将其封装...

程序袁_绪龙
2014/09/24
0
0
android自定义button样式

在Android开发应用中,默认的Button是由系统渲染和管理大小的。而我们看到的成功的移动应用,都是有着酷炫的外观和使用体验的。因此,我们在开发产品的时候,需要对默认按钮进行美化。在本篇...

sumpower
2014/02/25
0
0
Android开发:ScrollView嵌套GridView的解决办法

前些日子在开发中用到了需要ScrollView嵌套GridView的情况,由于这两款控件都自带滚动条,当他们碰到一起的时候便会出问题,即GridView会显示不全。 解决办法,自定义一个GridView控件 publ...

小0426小
2013/05/30
0
0
仿MIUI音量变化环形进度条实现

Android中使用环形进度条的业务场景其实蛮多的,比如下载文件的时候使用环形进度条,会给用户眼前一亮的感觉;再比如我大爱的MIUI系统,它的音量进度条就是使用环形进度条,尽显小米"为发烧而...

Jack_1900
2014/07/25
0
0
android 中 scollView中嵌套GridView显示UI不全

的解决办法 前些日子在开发中用到了需要ScrollView嵌套GridView的情况,由于这两款控件都自带滚动条,当他们碰到一起的时候便会出问题,即GridView会显示不全。 解决办法,自定义一个GridVie...

xiahuawuyu
2013/01/07
0
0
Android自定义控件以及控件属性的自定义

自定义控件在android中无处不见,自定义控件给了我们很大的方便。比如说,一个视图为imageview ,imagebutton ,textview 等诸多控件的组合,用的地方有很多,我们不可能每次都来写3个的组合,...

蜗牛崛起
2015/08/14
0
0
Android自定义View的实现(四)

如果说要按类型来划分的话,自定义View的实现方式大概可以分为三种,自绘控件、组合控件、以及继承控件。那么下面我们就来依次学习一下,每种方式分别是如何自定义View的。 一、自绘控件 自绘...

JayPark不作死
2014/07/02
0
0
android--------自定义控件 之 基本流程篇

在我们平常的Android开发中经常和控件打交道,有时Android提供的控件未必能满足业务的需求,这个时候就需要我们实现自定义一些控件 自定义控件可以设计出很多你想要的功能和模块,在开发中是...

切切歆语
04/30
0
0
android 打包自己的自定义组件成JAR包

在项目开发过程中,我们难免会用到自己去制作自定义的VIEW控件,之后我们别的项目如果需要的话就直接将其复制到对应的项目中使用,虽说这么做是一个解决问题的方法,但毕竟不是很好。 原因是...

刘遇安
2013/04/19
0
3
Android如何自定义头像控件

![在此输入图片描述][1] 如上图效果:效果分析 根据上面的效果,我们目测需要自定义两个控件,一个就是我们的可自由缩放移动的ImageView,一个就是那个白色的边框;然后一起放置到一个Relat...

crossmix
2015/04/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

10.28 rsync工具介绍 , rsync常用选项, rsync通过ssh同步

rsync远程同步 重点!重点!!重点!!! 例子 • rsync -av /etc/passwd /tmp/1.txt • rsync -av /tmp/1.txt 192.168.188.128:/tmp/2.txt rsync格式 • rsync [OPTION] … SRC DEST • rs......

Linux_老吴
15分钟前
0
0
iis php 环境搭建,非常详细的教程

准备篇 一、环境说明: 操作系统:Windows Server 2016 PHP版本:php 7.1.0 MySQL版本:MySQL 5.7.17.0 二、相关软件下载: 1、PHP下载地址: http://windows.php.net/downloads/releases/ph...

T_star
17分钟前
0
0
Day35 rsync通过服务同步

rsync通过服务同步 rsyncd.conf配置文件详解 port:指定在哪个端口启动rsyncd服务,默认是873端口。 log file:指定日志文件。 pid file:指定pid文件,这个文件的作用涉及服务的启动、停止等...

杉下
22分钟前
0
0
【最新最全】为 iOS 和 Android 的真机和模拟器编译 Luajit 库

编译 Luajit 库,的确是一个挑战。因为官网的教程,在当前版本的 Xcode 和 NDK 环境中,已经不适用了。以前只是编译了适用于真机的 Luajit 库。最近在尝试编译模拟器 Luajit 库,就顺便梳理了...

ios122
22分钟前
0
0
rsync至ssh同步

rsync: 文件同步工具,可实现“增量拷贝”;使用yum安装rsync包 常用选项:-a=-rtplgoD (-r同步目录,-t保持文件的时间属性,-p保持文件的权限属性,-l保持软连接,-g保持文件的属组,-o保持...

ZHENG-JY
28分钟前
0
0
TradingView 学习笔记

#前言 公司最后需要使用TradingView展示K线图走势。由于之前没接触过,拿到文档时一脸蒙逼。还好找到二篇文章+Demo代码,直接改改就行了。 #被批 由于上面的懵懂,有个问题困扰4个小时没解决...

hihubs
28分钟前
0
0
10.28 rsync工具介绍~10.31 rsync通过ssh同步

rsync命令是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件。rsync使用所谓的“rsync算法”来使本地和远程两个主机之间的文件达到同步,这个算法只传送两个文件的不同部分,而...

洗香香
30分钟前
1
0
php如何使用JSON-RPC查找以太坊中的最新块哈希hash值?

我用PHP中开发了一个以太坊块资源管理器,并成功地与我的服务器Geth节点建立了JSON-RPC通信。然而,当我试图找出最后一个区块时,我陷入了困境。我在https://ethereum.gitbooks.io/frontier...

智能合约
36分钟前
1
0
卷积为什么要旋转180度

参考《最容易理解的对卷积(convolution)的解释》 https://blog.csdn.net/bitcarmanlee/article/details/54729807 这篇博客详细讲解了“卷积”,提及了为什么要反转180度,我简述下。 1.卷积的...

datadev_sh
39分钟前
0
0
【2018.07.18学习笔记】【linux高级知识 20.23-20.26】

20.23/20.24/20.25 告警系统邮件引擎 告警系统邮件引擎由两个文件组成,放在/mon/mail/目录下:mail.py、mail.sh mail.py:是邮件的核心python脚本,邮件功能的实现mail.sh:是告警邮件系统...

lgsxp
44分钟前
16
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部