Android自定义控件开发系列(一)——第一次动手做自定义控件

        Android系统提供的控件多种多样,以至于很多初学者经常忘了还有这样那样的控件没用过甚至没听过。尽管如此,但是系统控件大多比较死板,而且不够美观,很多多样化的显示或是交互方式都没法完成。每每遇到这种情况,就需要我们来开发我们自己的控件了——所谓的“自定义控件”。接下来我们就一步一步扎扎实实的从头开始Android自定义控件的开发。

        废话少说,开始吧:

        一、实现自定义控件的3种主要方式

        (1)修改已有控件——继承已有控件,重写其显示、响应等;

        (2)组合已有控件——将已有的系统控件组合成一个独特的控件(接下来的示例中就是这种演示);

        (3)开发全新的控件——一般继承View或SurfaceView。他们都提供一个Canvas(画布)和一系列的画的方法,还有Paint(画笔)。使用它们去创建一个自定义的UI。你可以重写事件,包括屏幕接触或者按键按下等等,用来提供与用户交互。这种方式比较高阶,需要熟悉View的工作原理并熟悉其各个回调方法。

        二、为自定义控件增加属性的两种方法:

        (1)在自定义类中定义属性字段

         本文通过开发一个可以显示文字和图片组合的控件来加以说明。

       通过构造函数中引入的AttributeSet 去查找XML布局的属性名称,然后找到它对应引用的资源ID去找值:

public class MyView1 extends View {
    private String mtext;
    private int msrc;

    public MyView1(Context context) {
        super(context);
    }

    public MyView1(Context context, AttributeSet attrs) {
        super(context, attrs);

        //方法attrs.getAttributeResourceValue(String nameSpace, String attriName, int default)的nameSpace参数传null即可————
        int textId = attrs.getAttributeResourceValue(null, "Text", 0);
        int imgId = attrs.getAttributeResourceValue(null, "Img", 0);

        //根据传来的id找出字符串,比如示例代码中传入的是@stirng/hello_world
        //这里也可以直接在xml文件中设置字符串的参数但是获取属性值的方法就要相应变成
        //mtext = attrs.getAttributeValue(null, "Text")直接获取传入的字符串
        mtext = getResources().getText(textId).toString();
        msrc = imgId;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setTextSize(30);

        InputStream is = getResources().openRawResource(msrc);
        Bitmap bitmap = BitmapFactory.decodeStream(is);
        int imgWid = bitmap.getWidth();
        int imgHei = bitmap.getHeight();
        canvas.drawBitmap(bitmap, 0, 0, paint);
        canvas.drawText(mtext,imgWid/3, imgHei/2, paint);
    }
}

        然后在布局文件中使用我们自定义的控件(控件名要用包名+类名):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.wangj.cusview.MyView1
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        Img="@drawable/xx"
        Text="@string/hello_world" />
</RelativeLayout>

         运行一下如下图:

       

        到这里,可能会有人问,布局文件里自定义控件的属性设置直接用Img="@drawable/xx"和Text="@string/hello_world",怎么不像系统控件的属性那样的写法android:layout_height="wrap_content"呢?这里就需要回顾一下上边我们在上边MyView1类中用attrs.getAttributeResourceValue(String nameSpace, String attriName, int default)方法时的nameSpace参数传了个null,没有使用命名空间。

        ----------------------------------------------好了,上边这种方法完成了,下边的和上边的一样,只是更规范而已----------------------------------------------

        什么是命名空间呢?呵呵,你就先理解成一个归属吧,就像你们学校有好多个叫“王小二”的同学,校长要叫王二小同学来办公室聊聊,这是就要指出是“哪个班的王二小”了,命名空间就相当于这个班级的作用。我们看布局文件,根节点属性中都会有xmlns:android="http://schemas.android.com/apk/res/android"这一句,这就是声明一个命名空间,“命名空间的名字”就叫android,接下来就可以用android:layout_height="wrap_content"这种写法了。

        接下来我们也将上边的布局文件改成这种方式(我们也自己给一个命名空间)(这里需要说明一下,有人认为系统组件的命名空间必须要用“android”,其实不是的。“android”只是命名空间的名称,“http://schemas.android.com/apk/res/android”才是命名空间,你把xmlns:android="http://schemas.android.com/apk/res/android"改成xmlns:abcd="http://schemas.android.com/apk/res/android",在系统组件属性用abcd:layout_width也是没有问题的):   

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myview="http://blog.youkuaiyun.com/a_running_wolf"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!--这里第二行xmlns:my="http://blog.youkuaiyun.com/a_running_wolf"就是自己定义的命名空间-->
    <!--***注意这里的http://blog.youkuaiyun.com/a_running_wolf要和自定义类中的nameSpace一致,否则属性找不出来的-->

    <com.wangj.cusview.MyView1
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        myview:Img="@drawable/xx"
        myview:Text="@string/hello_world" />  <!--上边定义了命名空间,这里就可以像系统控件的属性一样的写法了-->

</RelativeLayout>

        相应的,在MyView1中就应该使用我们声明的这个命名空间了,直接看代码(这个类应该先于布局文件创建,不然在布局文件中怎么会有自己的控件可以用呢?这里放在后边主要是让大家重点看“命名空间”):

public class MyView1 extends View {
    //要和布局文件中声明的命名空间一致
    private final String nameSpace = "http://blog.youkuaiyun.com/a_running_wolf";
    private String mtext;
    private int msrc;

    public MyView1(Context context) {
        super(context);
    }

    public MyView1(Context context, AttributeSet attrs) {
        super(context, attrs);
        int textId = attrs.getAttributeResourceValue(nameSpace, "Text", 0);   //参数nameSpace用我们的命名空间
        int imgId = attrs.getAttributeResourceValue(nameSpace, "Img", 0);
        mtext = getResources().getText(textId).toString();
        msrc = imgId;
    }

    //onDraw方法和上边的一样
    .......
 }
        改造完毕,运行一下和上边一致:

       

        显然这种方式能实现相应的效果,但是效果很不好,文字显示在图片的什么地方、如果文字很多图片很小呢、如果我要改文字位置还要手动改drawText的位置参数,那么我们来看更规范的做法——往下看。

        (2)通过XML资源文件为自定义控件注册属性(和Android系统提供属性的方式一致)
        通过XML资源文件为控件注册属性,并使用命名空间的方式就是Android系统控件的属性提供方法,所以这种方式是推荐的自定义控件开发方法。首先在value目录下创建attrs.xml文件(有的话就不用创建了,直接往进写),写入如下的属性字段和相应的值(当然这里是根据自己的需要写,如下只是示例):

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyView2">
        <attr name="Text" format="reference|string" />
        <attr name="Oriental">
            <enum name="Herizontal" value="1" />
            <enum name="Vertical" value="0" />
        </attr>
        <attr name="Img" format="reference|integer" />
    </declare-styleable>
</resources>

        创建好attrs.xml后就可以用这些属性字段了(前提是你先创建好MyView2,否则控件啊!可以先创建一个空类,构造方法具体实现先不写,等后边在具体实现):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:TV="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="@dimen/activity_vertical_margin">
    <!-- 有的博客上说这里自己的命名空间要用“http://schemas.android.com/apk/包名”,但是我在AndroidStudio1.3.2、Android5.0时
    用“http://schemas.android.com/apk/res-auto”更智能一点 -->

    <com.wangj.cusview.MyView2
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        TV:Text="@string/app_name"
        TV:Img="@drawable/xx"
        TV:Oriental="Herizontal"/>
</RelativeLayout>

       附上MyView2的实现类: 

public class MyView2 extends LinearLayout {   //为了简单,这里继承LinearLayout
    public MyView2(Context context) {
        super(context);
    }

    public MyView2(Context context, AttributeSet attrs) {
        super(context, attrs);
        int resourceId = -1;
        
        //获取布局文件中对应控件的属性
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyView2);
        ImageView iv = new ImageView(context);
        TextView tv = new TextView(context);
        int N = typedArray.getIndexCount();
        for (int i = 0; i < N; i++){
            int attr = typedArray.getIndex(i);
            switch (attr){
                case R.styleable.MyView2_Text:
                    resourceId = typedArray.getResourceId(R.styleable.MyView2_Text, 0);
                    tv.setText(resourceId > 0 ? getResources().getText(resourceId) : typedArray.getString(R.styleable.MyView2_Text));
                    break;
                case R.styleable.MyView2_Img:
                    resourceId = typedArray.getResourceId(R.styleable.MyView2_Img, 0);
                    iv.setImageResource(resourceId > 0 ? resourceId : R.mipmap.ic_launcher);
                    break;
                case R.styleable.MyView2_Oriental:
                    resourceId = typedArray.getInt(R.styleable.MyView2_Oriental, 0);
                    this.setOrientation(resourceId == 1 ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL );
                    break;
            }
        }

        //记住要将TextView和ImageView都addView,否则什么都显示不了
        addView(iv);
        addView(tv);
        typedArray.recycle();   //释放资源
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    }
}

      MainActivity中没有做任何逻辑。直接运行,看效果:


        这里看到这个红色框中就是我们的MyView2控件(不包括红色框)。肯定有人问,这里看起来这个控件就和一个ImageView和一个TextView水平线性排列就一个样子啊?其实是的,但是区别在于——这里是一个控件,而不是两个控件——这里是为了简单演示,就简单的让MyView2继承了LineraLayout。根据实际的需求,我们可已让它继承RelativeLayout......各种布局,再创建自己的属性根据属性来做出漂亮的控件;可以继承已有的系统控件,重写其构造方法或是覆盖其onDraw方法来扩展出自己的个性化控件。

        这些都是自定义控件开发最基础的知识,接下来我们将逐步深入,开发更高级和更美观的自定义控件,我也是在边学边写,如有不足希望大家指出,一起讨论,一起进步,也希望大家继续关注我的文章。

相关推荐

深究Java foreach循环的实现原理和其中的坑

集合、数组的遍历是必不可少的开发工具,foreach又是那么甜,二者走到一起会发生什么呢?这篇文章带你一起尝一尝其中的酸甜苦辣!

衷水木先生的博客 4429

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(4)完结篇

在这个系列的前几篇文章中,从最初简单的服务器环境搭建、MySQL数据库的安装、Servlet 的原理及使用、数据库的连接及CURD操作、Android和服务器GET/POST数据交互,到最后JSon格式报文的使用,我们已经将这个过程完整的走完一遍,但是其中用的代码都是片段式的,没有一个清晰的结构,甚至有些代码只是单纯地为了说明用法,还有一些朋友提出说代码中有一些自定义的方法没有说明,所以我们最后来一个总结篇,把之前的代码优化规整一下,顺便把之前的一些问题明确一下。 先从 Android 部分

衷水木先生的博客 1万+

VMware虚拟机能ping通宿主机,但宿主机ping不通虚拟机

VMware 安装完虚拟机,检查网络联通性时候发现了比较奇怪的现象:宿主机、虚拟机都是可以访问外网的,虚拟机 ping 宿主机正常,但是宿主机 ping 不通虚拟机正常。

衷水木先生的博客 1714

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(1)服务器环境搭建

做 Android 开发一年多了,虽然不敢说有多精通,但也相对熟悉。做久了就会发现 Android 在行外人眼中是多么高深(包括 IOS 也一样),但是我们自己知道其实 Android 和 Web 前端其实本质上是没有多大的区别,只不过一个是显示在浏览器中,一个是显示在手机上而已。慢慢地,你会发现移动端(Android、IOS、WinPhone、WebAPP)其实涉及到的业务逻辑是很少很少的——无关孰优孰劣,这是分工的不同,移动端毕竟硬件资源有限,适合于简单的计算和交互处理,业务逻辑什么的放在资源更富裕的服

衷水木先生的博客 7万+

【相机】(2)——WebView中打开相机、文件选择器的问题和解决方法

上一篇[Intent调相机的2种方式以及那些你知道的和不知道的坑]中完成了对 Intent 调起系统相机、结果处理以及一些问题的应对。其实上篇文章还是因为今天的主题 **WebView中调用系统相机** 而起,因为涉及到调用相机本身的一些问题之前不是很明确,所以专门搞了一下,记录下来,所以如果调

衷水木先生的博客 1万+

【相机】(1)——Intent调相机的2种方式以及那些你知道的和不知道的坑

要不要都行的开篇随着现代信息量的疯狂增长、信息的快速交流,单纯的文字信息已经难以满足日常、工作的沟通,一张图片往往能达到一图胜过千万言的效果,前段时间不是盛行“有图有真相的”说法;还有一些场景则需要通过上传照片来验证身份的合法性,比如手机银行要求上传身份证正反照,手持身份证照 ……废话多了点,总之,作为移动端开发者的你,肯定会遇到这样那样拍照上传的需求,接下来我们来试试 Intent 调用 Andr

衷水木先生的博客 4470

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(3-3)Json数据交互

这篇文章实在是耽搁了太久了,唉,人生呐,怎一个懒字了得!都不好意思扯会儿淡了,进入正题吧。上篇我们将 Android 和 Servlet 进行 POST 方式进行数据交互搞通了,但是在例子中传输的数据是以最简单的 String 类型来举例的,下边我们就来用现在流行的 JSON 格式跑一个。Json,是个轻量级的数据交换格式,但具体有什么优劣、使用场景有哪些、或者和别的数据格式对比如何,这些不是我们本

衷水木先生的博客 1万+

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(3-2)Android 和 Service 的交互之POST方式

今天是圣诞节,虽说我本人对这个西方节日没什么感觉,但毕竟还是有很多小年轻人(自认为已然脱离年轻人的航道)挺在意这个节日的,在这里祝大家圣诞快乐吧(要是凑巧你也没什么感觉,那就预祝元旦快乐)!        闲话少叙,继续我们的正题。得益于上一篇文章【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(3-1)Android 和 Service 的交互之GET方式 所做的思路修改,我

衷水木先生的博客 1万+

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(3-1)Android 和 Service 的交互之GET方式

好久没更新了,罪过罪过。最对不起的人莫过于那些支持和等待在下拙文的诸位,在此道一声抱歉。管窥之见,侥幸博得各位认同,给了我莫大的鼓励。        话休絮烦,文接前章。        到【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(2-3)Servlet连接MySQL数据库为止,我们已经将服务端的部分走通了:通过 Servlet 连接 MySQL ,分析业务需求进行响

衷水木先生的博客 3万+

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(2-3)Servlet连接MySQL数据库

在【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(1)服务器环境搭建中我们搭建了完整的服务器开发环境,但是接下来的两篇介绍 Servlet 的并没有用到 MySQL数据库,因为仅有的验证登录业务也是模拟的,今天我们就来说说 Servlet 中使用 MySQL 的方法。

衷水木先生的博客 3万+

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(2-2)Servlet的使用

在上一篇【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(2-1)Servlet 的使用中我们只是简单的对 Servlet 的任务、在服务器中的地位有了一个大概的了解,完成了在一个全新的 WorkSpace 中创建第一 Dynamic Web Project ,并创建第一个 Servlet ,解决期间可能遇到的常见问题,还留了不少的内容重要内容没有完成,今天我们来继续完成这些:

衷水木先生的博客 2万+

【一步一个脚印】Tomcat+MySQL为自己的APP打造服务器(2-1)Servlet的使用

服务器接收来自不同用户的不同的请求(当然是以该服务器作为请求目标的那些请求),分析不同的请求,控制模块将各自的请求分送至对应的 Servlet (如登陆请求,则将登陆数据送至LoginServlet),然后 Servlet 根据请求内容处理业务逻辑(如登陆请求则解析用户名密码,并和数据库中保存的用户名密码进行对比,得出是否是合法用户的结论),完成响应数据的封装返回给控制模块,控制模块再将该响应返回给对应的请求用户,这样即完成一次网络交互。

衷水木先生的博客 3万+

SVN问题之——org.apache.subversion.javahl.ClientException: Attempted to lock an already-locked dir

今天在 Eclipse 中用 SVN 插件提交代码时遇到 org.apache.subversion.javahl.ClientException: Attempted to lock an already-locked dir 的问题,"SVN 客户端异常:试图锁定一个已经锁定的目录"。提交代码的时候,SVN 所做的工作中有一个操作步骤是"锁定",所以才会有"Attempted to lock "这一步,至于"an already-locked dir",我忽然想到,昨晚下班我尝试过一次提交代码,但是由于

衷水木先生的博客 6万+

APP接入QQ登陆功能报错“该应用非官方正版应用,请到......100044”的几种错误

最近在学习APP接入“QQ登陆”功能时,一动手就遇到遇到“该应用非官方版本正版应用,请去应用宝下载正版后进行qq登录。(错误码100044)”的问题,如下图:                捣鼓来捣鼓去就是不知道哪里出的问题,腾讯开发平台的文档都翻了十几遍也没有相关的问题说明,还是网上有大神啊,陆陆续续找出来一些会导致此错误的情况进行记录,给遇到同样问题的你提供一条捷径。

衷水木先生的博客 5万+

ListView点击Item展开隐藏项(单项展开、多项展开、复杂布局时的展开处理)

手机屏幕毕竟有限,当我们要显示较多数据时便不得不舍去一些次要信息,将主要信息优先显示,也使显示效果更加简洁美观。遇到类似的需求,我们使用最多的就是 ListView ,而如果每次点击一个 Item 都要跳转到下一页查看详情,查看另一个还要返回列表重新进入另一条详情,使得操作繁琐体验降低。此时可隐藏和展开 Item 的 ListView 便应运而生,这不是一个新的控件,只是我们灵活使用造出来的用法,下边我就来实现 ListView 点击 Item 展开隐藏项,包括列表单项展开、多项展开、复杂布局展开的实现,先

衷水木先生的博客 1万+

Activity设置全屏显示的两种方式及系统自带theme属性解析

设置Activity隐藏标题栏、设置Activity全屏显示在我们开发中会经常用到,毕竟手机屏幕大小有限,有时候是为了显示更多的信息而舍弃一些不必要的界面开支,首当其冲的就是标题栏,接下来就是状态栏;有时候是为了界面的简洁和美观……不举例子了,相信你肯定遇到过这样的需求,直接入正题: 设置隐藏标题栏、全屏显示常用的有2种方法(和Android开发中大多数属性的设置方法一样)

衷水木先生的博客 1万+

Android完美获取状态栏高度、标题栏高度、编辑区域高度的获取

简单说明一下(上图Activity采用默认Style,状态栏和标题栏都会显示):最大的草绿色区域是屏幕界面,红色次大区域我们称之为“应用界面区域”,最小紫色的区域我们称之为“View绘制区域”;屏幕顶端、应用界面区之外的那部分显示手机电池网络运营商信息的为“状态栏”,应用区域顶端、View绘制区外部显示Activity名称的部分我们称为“标题栏”。下边给出4中状态栏高度获取和2种标题栏获取高度的方法——

衷水木先生的博客 9万+

Android 视图框架系列2/3——SurfaceView视图框架

SurfaceView 继承于 View ,所以同样拥有触屏监听、按钮监听等方法,但是请注意,SurfaceView 看名字就和 Surface 脱不了干系,Surface 是 Android 中一个很重要的类,有必要了解一下。每个 View 在和屏幕绑定时都会关联一个对应的 Surface,你可以把 Surface 理解成一块屏幕缓存。但从源码可以看出 SurfaceView 还有一个 Surface 类型的成员变量,所以 SurfaceView 就拥有了两个内存区。 这里就该说 SurfaceView

衷水木先生的博客 2918

Android 视图框架系列1/3——View视图框架

View 是 Android 开发中最基础也是最本质的视图基类,在开发中要想实现自定义的控件,大多都是直接继承自View,因为那些可以继承View的子类(甚至是子类的子类)的控件其实都是修修改改,只是接触到自定义控件的皮毛而已。具体还是看Android自定义控件开发系列(零)——基础原理篇吧,不必再重复了。 不管是游戏开发还是内容性 APP 开发,继承 View 主要还是重写 onDraw(Canvas canvas)、onTouchEvent(MotionEvent event)、onKe

衷水木先生的博客 2179

闲话Android游戏开篇

游戏,这个词专门查了一下词典,还真没有什么明确的定义。什么是游戏,可能没必要给它下个明确的定义,也没有实际的意义,只要有主体参与的以获取快感为目的的活动都可以称之为游戏。这里指出了游戏的两个要素:参与主体和获取快感的目的。请不要产生“你怎么在这瞎扯蛋,我又不是来学哲学的”的想法,我解释这个是有目的的——

衷水木先生的博客 1376

Android自定义控件开发系列(三)——仿支付宝六位支付密码输入页面

在移动互联领域,有那么几家龙头一直是我等学习和追求的目标,比如支付宝、微信、饿了么、酷狗音乐等等,大神举不胜举,他们设计的界面、交互方式已经培养了中国(有可能会是世界)民众的操作习惯:举个小例子,对话框“确定”按钮的左右位置就很有学问,如果大家都是左边取消右边确定,你的作品偏偏相反,就会导致用户在操作时候很不适应,甚至会习惯性点错,这一小小的问题将严重影响产品的体验,闲话少说,开始...

衷水木先生的博客 2万+

Android开发中经常用到的工具

本文总结Android开发中经常会用到的各种工具,包括一些好的工具软件、资源类网站等。对于一些需要注册什么的,如果你嫌麻烦,我也提供了我的帐号密码给你用(反正就是下载一些东西,没啥风险吧,希望你好用,但是不要随意粘贴,谢了)。 全是本人亲身实践总结,绝无虚假编造之举,不定时更新,敬请期待。

衷水木先生的博客 1663

老程序员给初学者的一些建议和忠告

网上看到的一篇好文章,自己当年没有读到是损失,现在希望更多的师弟师妹因为这篇文章避免这个损失!请记住——我不会以码农自卑,但一定以常年码农为耻!

衷水木先生的博客 9771

用shape、selector自定义样式美化控件

有的人说“自定义控件”,不错,自定义控件能实现这样的效果,甚至更加美好,这个毋庸置疑!但是这里用自定义控件显然大材小用了——如果仅仅要求这些显示效果的话,根本用不到自定义控件这样的大工程——简简单单一个样式文件(shape或selector)就搞定了,下边我们来详细看看这两种文件

衷水木先生的博客 1883

Java/Android中的函数调用&回调函数&自定义回调函数

在Android的学习过程中经常会听到或者见到“回调”这个词,那么什么是回调呢?所谓的回调函数就是:在A类中定义了一个方法,这个方法中用到了一个接口和该接口中的抽象方法,但是抽象方法没有具体的实现,需要B类去实现,B类实现该方法后,它本身不会去调用该方法,而是传递给A类,供A类去调用,这种机制就称为回调。其实,回调函数就是在一个不确定实现的方法METHOD中用interface或者它的抽象方法留个口子,留给具体调用者(调用前边那个不确定的方法METHOD)在调用时提供具体实现来补上那个口子。从而达到更灵活地

衷水木先生的博客 3万+

Android自定义控件开发系列(零)——基础原理篇

在后边的文章中发现在说Android自定义时,有时候要重复解释很多东西,所以想想返回来增加一篇“基础原理篇”,直接进入正题吧—— 首先的问题是:在Android项目开发中,什么时候需要自定义控件呢? 我们在日常开发中,可能会想到很好的项目方案(那么恭喜你,你很有产品经理的素养和潜质),或者是遇到很好的设计方案(也恭喜你,你遇到一个很有品味和审美的...

衷水木先生的博客 3230

Android自定义控件开发系列(二)——带清除按钮的圆角输入框

接着上一篇Android自定义开发系列(一)继续:        由于上一篇的例子做得比较粗糙,也是因为那个只是个简单的入门,只是演示了一下通过组合已有控件开发自定义控件的几个途径。那样的例子连自己都感觉不好意思啦,那么今天我来做一个稍微美观、实用、性能更好的自定义控件,也是大家在平时开发中使用广泛的控件——自定义一个带清除按钮的输入框,先看一下效果:

衷水木先生的博客 3724

Android之Activity之间的数据通信方式大全(二)

接着上篇Android之Activity之间的数据通信方式大全(一)继续(3)使用SharedPreference实现Activity之间的数据通信SharedPreference是Android中最简单的文件本地化存储方式,Android API也提供相当简单的方式来进行读写操作。

衷水木先生的博客 3774

Android之Activity之间的数据通信方式大全(一)

最近二期项目正在讨论需求,本人小小程序员只有搞搞维护的份。刚工作不久,技术经验不足,随时准备找份更好的工作,闲来无事,看看Android面试经典啥的,就看到有问Activity之间数据通信方式都有哪些(*只是Activity之间通信,不讨论Service、Broadcast),忽然想想自己也不是很确定了解的全不全。看了挺多文档,大多只涉及到其中几点,现在整理一下,共自己和大家参考,如有欠缺欢迎留言指

衷水木先生的博客 1万+

Android Studio错误代码不提示问题解决

由于最近项目需求,我们项目组决定将之前的项目从Eclipse搬到Android Studio上来,毕竟google花大力气为亲儿子定制的IDE肯定比Eclipse走的更远!废话少说,在AS的使用时确实遇到不少问题,比如快捷键的设置、工程结构的变化、软件的使用习惯等等。 下面解决一个坑死人的“大坑”——之前熟悉过AS,今天打开AS升级了一下版本,打开以后新建工程……试着随意写几行代码练练手,

衷水木先生的博客 3万+
上一篇: Android之Activity之间的数据通信方式大全(二)
下一篇: Android自定义控件开发系列(二)——带清除按钮的圆角输入框
衷水木先生
衷水木先生 企业官方账号 企业官方账号
博客等级 码龄12年 1011粉丝 30原创
评论 18
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值