自定义View入门

简介: 自定义View入门

在Android应用开发过程中,固定的一些控件和属性可能满足不了开发的需求,所以在一些特殊情况下,我们需要自定义控件与属性。



一、实现步骤


  1. 继承View类或其子类 
  2. 复写view中的一些函数
  3. 为自定义View类增加属性(两种方式)
  4. 绘制控件(导入布局)
  5. 响应用户事件
  6. 定义回调函数(根据自己需求来选择)



二、哪些方法需要被重写


  • onDraw()
      view中onDraw()是个空函数,也就是说具体的视图都要覆写该函数来实现自己的绘制。对于ViewGroup则不需要实现该函数,因为作为容器是“没有内容“的(但必须实现dispatchDraw()函数,告诉子view绘制自己)。
  • onLayout()

 主要是为viewGroup类型布局子视图用的,在View中这个函数为空函数。

onMeasure()

 用于计算视图大小(即长和宽)的方式,并通过setMeasuredDimension(width, height)保存计算结果。

onTouchEvent

 定义触屏事件来响应用户操作。

 


还有一些不常用的方法:

onKeyDown() 当按下某个键盘时  

onKeyUp() 当松开某个键盘时  

 

onTrackballEvent() 当发生轨迹球事件时  

 

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

 

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

 

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

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

 

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

 

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

View的绘制流程

绘制流程函数调用关系如下图:

20160617150747985.png


我们调用requestLayout()的时候,会触发measure 和 layout 过程,调用invalidate,会执行 draw 过程。



三.自定义控件的三种方式


1. 继承已有的控件

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


2. 继承一个布局文件

 一般用于自定义组合控件,在构造函数中通过inflater和addView()方法加载自定义控件的布局文件形成图形界面(不需要onDraw方法)。


3.继承view

 通过onDraw方法来绘制出组件界面。



四.自定义属性的两种方法


1.在布局文件中直接加入属性,在构造函数中去获得。


布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
     <com.example.demo.myView
         android:layout_width="wrap_content"
         android:layout_height="wrap_content" 
         Text="@string/hello_world"
         />
</RelativeLayout>


获取属性值:

public myView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
int textId = attrs.getAttributeResourceValue(null, "Text", 0);
String text = context.getResources().getText(textId).toString();
    }


2.在res/values/ 下建立一个attrs.xml 来声明自定义view的属性。

可以定义的属性有:

<declare-styleable name = "名称"> 
//参考某一资源ID (name可以随便命名)
<attr name = "background" format = "reference" /> 
//颜色值 
<attr name = "textColor" format = "color" /> 
//布尔值
<attr name = "focusable" format = "boolean" /> 
//尺寸值 
<attr name = "layout_width" format = "dimension" /> 
//浮点值 
<attr name = "fromAlpha" format = "float" /> 
//整型值 
<attr name = "frameDuration" format="integer" /> 
//字符串 
<attr name = "text" format = "string" /> 
//百分数 
<attr name = "pivotX" format = "fraction" /> 
//枚举值 
<attr name="orientation"> 
<enum name="horizontal" value="0" /> 
<enum name="vertical" value="1" /> 
</attr> 
//位或运算 
<attr name="windowSoftInputMode"> 
<flag name = "stateUnspecified" value = "0" /> 
<flag name = "stateUnchanged" value = "1" /> 
</attr> 
//多类型
<attr name = "background" format = "reference|color" /> 
</declare-styleable> 


attrs.xml进行属性声明

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="myView">
        <attr name="text" format="string"/>
        <attr name="textColor" format="color"/>
    </declare-styleable>
</resources>


添加到布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:myview="http://schemas.android.com/apk/com.example.demo"
    >
     <com.example.demo.myView
         android:layout_width="wrap_content"
         android:layout_height="wrap_content" 
         myview:text = "test"
         myview:textColor ="#ff0000"
         />
</RelativeLayout>



这里注意命名空间:

xmlns:前缀=”http://schemas.android.com/apk/res/包名(或res-auto)”,

前缀:TextColor 使用属性。


  • 在构造函数中获取属性值
public myView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.myView); 
        String text = a.getString(R.styleable.myView_text); 
        int textColor = a.getColor(R.styleable.myView_textColor, Color.WHITE); 
        a.recycle();
    }


 或者:

    public myView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.myView); 
        int n = a.getIndexCount();
        for(int i=0;i<n;i++){
            int attr = a.getIndex(i);
            switch (attr) {
            case R.styleable.myView_text:
                break;
            case R.styleable.myView_textColor:
                break;
            }
        }
       a.recycle();
    }




五. 自定义随手指移动的小球(小例子)


20160503143613554.gif


实现上面的效果我们大致需要分成这几步


   在res/values/ 下建立一个attrs.xml 来声明自定义view的属性

   一个继承View并复写部分函数的自定义view的类

   一个展示自定义view 的容器界面  


1.自定义view命名为myView,它有一个属性值,格式为color:


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="myView">
        <attr name="TextColor" format="color"/>
    </declare-styleable>        
</resources>

2.在构造函数获取获得view的属性配置和复写onDraw和onTouchEvent函数实现绘制界面和用户事件响应。

public class myView extends View{
    //定义画笔和初始位置
    Paint p = new Paint();
    public float currentX = 50;
    public float currentY = 50;
    public int textColor;
    public myView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //获取资源文件里面的属性,由于这里只有一个属性值,不用遍历数组,直接通过R文件拿出color值
        //把属性放在资源文件里,方便设置和复用
        TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.myView);
        textColor = array.getColor(R.styleable.myView_TextColor,Color.BLACK);
        array.recycle();
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //画一个蓝色的圆形
        p.setColor(Color.BLUE);
        canvas.drawCircle(currentX,currentY,30,p);
        //设置文字和颜色,这里的颜色是资源文件values里面的值
        p.setColor(textColor);
        canvas.drawText("BY finch",currentX-30,currentY+50,p);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        currentX = event.getX();
        currentY = event.getY();
        invalidate();//重新绘制图形
        return true;
    }
}


这里通过不断的更新当前位置坐标和重新绘制图形实现效果,要注意的是使用TypedArray后一定要记得recycle(). 否则会对下次调用产生影响。

20160503144335969.jpg


3.把myView加入到activity_main.xml布局里面

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:myview="http://schemas.android.com/apk/res-auto"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="finch.scu.cn.myview.MainActivity">
    <finch.scu.cn.myview.myView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        myview:TextColor="#ff0000"
        />
</RelativeLayout>


4.最后是MainActivity

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}


   具体的view要根据具体的需求来,比如我们要侧滑删除的listview我们可以继承listview,监听侧滑事件,显示删除按钮实现功能。



欢迎start,欢迎评论,欢迎指正



相关文章
|
运维 监控 Linux
Linux Rsync服务详解(二)——Rsync服务实战
Linux Rsync服务详解(二)——Rsync服务实战
341 1
|
程序员 编译器 Linux
V 语言
V 是一门通用的编程语言,也可以作为系统语言,其网站说它非常简单,你可以在一个周末学会,它还说 Go 程序员会对该语言非常熟悉,因为 V 语言在很多方面借鉴了 Go。
607 2
|
移动开发 安全 JavaScript
uniapp打包成H5部署到服务器教程
uniapp打包成H5部署到服务器教程
2490 0
|
5月前
|
前端开发 API 开发者
一键抠图有多强?19Kstar 的 Rembg 开源神器,5 大实用场景颠覆想象!
Rembg是一款基于Python的开源抠图工具,利用深度学习模型(U-Net/U-2-Net)实现高质量背景移除。它支持命令行、Python API、服务端API及插件等多种形式,适用于电商商品图、社交头像优化、设计项目图像等场景。凭借高精准度、即插即用特性和全面生态,Rembg在GitHub上已获19.1K星,成为开发者社区中的热门工具。其本地部署特性确保数据隐私,适合专业与商业环境使用。项目地址:https://github.com/danielgatis/rembg。
1242 24
|
负载均衡 中间件 应用服务中间件
中间件负载均衡
【7月更文挑战第21天】
699 6
|
11月前
|
人工智能 自然语言处理 自动驾驶
当视觉大模型陷入认知失调,马里兰大学构建了一个幻觉自动生成框架
马里兰大学研究人员提出AutoHallusion框架,旨在通过自动化生成幻觉图像和问题对,深入研究大型视觉语言模型(LVLMs)中的幻觉现象。幻觉指LVLMs生成与图像内容不符的描述,限制其广泛应用。AutoHallusion通过异常对象插入、配对对象插入和相关对象删除三种策略,揭示LVLMs在处理视觉信息时的弱点。实验结果显示,该框架能在多种SOTA模型上以高成功率引发幻觉,为改进模型提供宝贵线索。未来将提升图像质量和扩展问题设计范围。论文链接:https://arxiv.org/pdf/2406.10900
188 27
|
10月前
|
C语言
【C语言程序设计——循环程序设计】鸡兔同笼问题(头歌实践教学平台习题)【合集】
本教程介绍了循环控制和跳转语句的使用,包括 `for`、`while` 和 `do-while` 循环,以及 `break` 和 `continue` 语句。通过示例代码详细讲解了这些语句的应用场景,并展示了如何使用循环嵌套解决复杂问题,如计算最大公因数和模拟游戏关卡选择。最后,通过鸡兔同笼问题演示了穷举法编程的实际应用。文中还提供了编程要求、测试说明及通关代码,帮助读者掌握相关知识并完成任务。 任务描述:根据给定条件,编写程序计算鸡和兔的数量。鸡有1个头2只脚,兔子有1个头4只脚。
538 5
|
人工智能 数据安全/隐私保护 开发者
AIGC带来的伦理之思
【1月更文挑战第13天】AIGC带来的伦理之思
810 4
AIGC带来的伦理之思
|
运维 监控 Java
在Linux中,当遇到系统卡顿时,你会采取哪些步骤来定位原因?
在Linux中,当遇到系统卡顿时,你会采取哪些步骤来定位原因?
|
Web App开发 前端开发 JavaScript
浏览器之性能指标-TBT
浏览器之性能指标-TBT
524 0