疯狂Android讲义(二)——第一部分:界面编程与视图 (View) 组件详解

这里主要针对一些控件和布局的使用,篇幅会有点长。而且,不会像第一章一样全部详细列出。本章主要会用知识点的方式展示内容。

 Android应用开发的—项内容就是用户界面的开发。不管应用实际包含的逻辑多么复杂、多么优秀,如果这个应用没有提供友好的图形用户界面(Graphics User Interface,GUI),也将很难吸引最终用户。

实际上,Windows之所以广为人知,其最初的吸引力就是来自于它所提供的图形用户界面

一、界面编程与视图 (View) 组件

  1.视图组件与容器组件

        Android应用的绝大部分UI组件都放在android.widget包及其子包、android.view包及其子包中Android应用的所有UI组件都继承了View类,View组件非常类似于Swing编程的JPanel,它代表一个空白的矩形区域。

        View类还有一个重要的子类:ViewGroup,但ViewGroup通常作为其他组件的容器使用。

        Android的所有UI组件都是建立在View、ViewGroup基础之上的,Android采用了“组合器"设计模式来设计View和ViewGroup: ViewGroup是View的子类,因此ViewGroup也可被当成View使用。对于一个Android应用的图形用户界面来说,ViewGroup作为容器来盛装其他组件,而ViewGroup里除了可以包含普通View组件之外,还可以再次包含ViewGroup组件。

        图2.1显示了Android图形用户界面的组件层次图。

        前面介绍Android应用结构时已经指出,Android推荐使用XML布局文件来定义用户界面,而不是使用Java代码来开发用户界面,因此所有组件都提供了两种方式来控制组件的行为。

  • XML布局文件中通过XML属性进行控制。
  • Java程序代码中通过调用方法进行控制。

        实际上不管使用哪种方式,它们控制Android用户界面行为的本质是完全一样的。大部分时候,控制UI组件的XML属性还有对应的方法。

        对于View类而言,它是所有UI组件的基类,因此它包含的XML属性和方法是所有组件都可使用的。如表所示是View类常用的XML属性、相关方法及简要说明。

XML属性相关方法说明
android:alphasetAlpha(float)设置该组件的透明度
android:backgroundsetBackgroundResource(int)设置该组件的背景颜色
android:backgroundTintsetBackgroundTintList(ColorStateList)设置对背景颜色重新着色,该属性要与android:background结合使用
android:backgroundTintModesetBackgroundTintMode(PorterDuff.Mode)设置对背景颜色着色的模式,该属性支持PorterDuff.Mode的各枚举值
android:clickablesetClickable(boolean)设置该组件是否可以激发单击事件
android:contentDescriptionsetContentDescription(CharSequence)设置该组件的内容描述信息
android:contextClickablesetContextClickable(boolean)设置该属性是否可以激发context单击事件
android:drawingCacheQualitysetDrawingCacheQuality(int)设置该组件所使用的绘制缓存的质量
android:elevationsetElevation(float)设置该组件“浮”起来的高度,通过设置该属性可让该组件呈现3D效果
android:fadeScrollbarssetScrollbarFadingEnabled(boolean)当不使用该组件的滚动条时,是否淡出显示滚动条
android:fadingEdgeLengthgetVerticalFadingEdgeLength()设置淡出边界的长度
android:filterTouchesWhenObscuredsetFilterTouchesWhenObscured(boolean)设置当该组件所在的窗口被其他窗口遮挡时,是否过滤触摸事件
android:fitsSystemWindowssetFitsSystemWindows(boolean)设置是否基于系统窗口(如状态栏)来调整视图布局
android:focusablesetFocusable(boolean)设置该组件是否可以得到焦点
android:focusableInTouchModesetFocusablelnTouchMode(boolean)设置该组件在触摸模式下是否可以得到焦点
android:foregroundsetForeground(Drawable)指定绘制到组件内容上面的Drawable
android:foregroundGravitysetForegroundGravity(int)设置绘制前景Drawable时的对齐方式
android:foregroundTintsetForegroundTint(ColorStateList)设置对前景Drawable重新着色
android:foregroundTintModesetForegroundTintMode(PorterDuff.Mode)设置对前景Drawable着色的模式
android:hapticFeedbackEnabledsetHapticFeedbackEnabled(boolean)设置该组件是否能对诸如长按这样的事件启动触觉反馈
android:idsetId(int)设置该组件的唯一标识。在 Java代码中可通过findViewByld来获取它
android:isScrollContainersetScrollContainer(boolean)设置该组件是否作为可滚动容器使用
android:keepScreenOnsetKeepScreenOn(boolean)设置该组件是否会强制手机屏幕一直打开
android:layerTypesetLayerType(int,Paint)设置该组件使用的图层类型
android:layoutDirectionsetLayoutDirection(int)设置该组件的布局方式。该属性支持Itr(从左到右)、rtl(从右到左) 、inherit(与父容器相同)和locale四种值
android:longClickablesetLongClickable(boolean)设置该组件是否可以响应长单击事件
android:minHeightsetMinimumHeight(int)设置该组件的最小高度
android:minWidthetMinimumWidth(int)设置该组件的最小宽度
android:nextFocusDownsetNextFocusDownld(int)设置焦点在该组件上,且单击向下键时获得焦点的组件ID
android:nextFocusForwardsetNextFocusForwardld(int)设置焦点在该组件上,且单击向前键时获得焦点的组件ID
android:nextFocusLeftsetNextFocusLeftld(int)设置焦点在该组件上,且单击向左键时获得焦点的组件ID
android:nextFocusRightsetNextFocusRightId(int)设置焦点在该组件上,且单击向右键时获得焦点的组件ID
android:nextFocusUpsetNextFocusUpId(int)设置焦点在该组件上,且单击向上键时获得焦点的组件ID
android:onClick为该组件的单击事件绑定监听器
android:paddingsetPadding(int,int,int,int)在组件的四边设置填充区域
android:paddingBottomsetPadding(int,int,int,int)在组件的下边设置填充区域
android:paddingEndsetPaddingRelative(int,int,int,int)相对布局中,在组件结尾处设置填充区域
android:paddingHorizontalsetPaddingRelative(int,int,int,int)在组件的左、右两边设置填充区域
android:paddingLeftsetPadding(int,int,int,int)在组件的左边设置填充区域
android:paddingRightsetPadding(int,int,int,int)在组件的右边设置填充区域
android:paddingStartsetPaddingRelative(int,int,int,int)相对布局中,在组件起始处设置填充区域
android:paddingTopsetPadding(int,int,int,int)在组件的上边设置填充区域
android:paddingVerticalsetPadding(int,int,int,int)在组件的上、下两边设置填充区域
android:rotationsetRotation(float)设置该组件旋转的角度
android:rotationXsetRotationX(float)设置该组件绕X轴旋转的角度
android:rotation YsetRotationY(float)设置该组件绕Y轴旋转的角度
android:saveEnabledsetSaveEnabled(boolean)如果设置为false,那么当该组件被冻结时不会保存它的状态
android:scaleXsetScaleX(float)设置该组件在水平方向的缩放比
android:scaleYsetScaleY(float)设置该组件在垂直方向的缩放比
android:scrollIndicatorssetScrollIndicators(int)设置组件滚动时显示哪些滚动条,默认值是" top|bottom",即上、下显示
android:scrollX该组件初始化后的水平滚动偏移
android:scrollY该组件初始化后的垂直滚动偏移
android:scrollbarAlwaysDrawHorizontalTrack设置该组件是否总是显示水平滚动条的轨道
android:scrollbarAlwaysDraw VerticalTrack设置该组件是否总是显示垂直滚动条的轨道
android:scrollbarDefaultDelayBeforeFadesetScrollBarDefaultDelayBeforcFade(int)设置滚动条在淡出隐藏之前延迟多少毫秒
android:scrollbarSizesetScrollBarSize(int)设置垂直滚动条的宽度和水平滚动条的高度
android:scrollbarStylesetScrollBarStyle(int)

设置滚动条的风格和位置。该属性支

持如下属性值:

➢insideOverlay

➢insideInset

➢outsideOverlay

➢outsideInset

android:scrollbarThumbHorizontal设置该组件的水平滚动条的滑块对应的Drawable对象
android:scrollbarTrackVertical设置该组件的垂直滚动条的轨道对应
的Drawable对象
android:scrollbars定义该组件滚动时显示几个滚动条。
该属性支持如下属性值:
➢none: 不显示滚动条
➢horizontal: 显示水平滚动条
➢vertical:显示垂直滚动条
android:soundEffectsEnabledsetSoundEffectsEnabled(boolean)设置该组件被单击时是否使用音效。
android:tag为该组件设置一 个字符串类型的tag值 。接下来可通过View的getTag()获取该字符串,或通过findViewWithTag()查找该组件
android:textAlignmentsetTextAlignment(int)设置组件内文字的对其方式
android:textDirectionsetTextDirection(int)设置组件内文字的排列方式
android:theme设置该组件的主题
android:transformPivotXsetPivotX(float)设置该组件旋转时旋转中心的X坐标
android:transformPivotYsetPivotY(float)设置该组件旋转时旋转中心的Y坐标
android:transitionName为该View指定名字以便Transition能识别它
android:translationXsetTranslationX(float)设置该组件在X方向上的位移
android:translationYsetTranslationY(float)设置该组件在Y方向上的位移
android:translationZsetTranslationZ(float)设置该组件在Z方向(垂直屏幕方向)上的位移
android:visibilitysetVisibility(int)设置该组件是否可见

注意:

上面表格中介绍View组件时列出的setBackgroundTintList、setElevation (float) 和setTranslationZ(float) 方法都是Android 5.0新增的Material Design中的功能,它们的作用也基本相似,它们都可用于设置该组件垂直屏幕“浮”起来的效果,通过该属性可让该组件呈现3D效果。当该组件垂直于屏幕“浮”起来之后,组件下的实时阴影就会自动显现。

        ViewGroup继承了View类,当然也可以当成普通View来使用,但ViewGroup主 要还是当成容器类使用。但由于ViewGroup是一个抽象类,因此实际使用中通常总是使用ViewGroup的子类来作为容器,例如各种布局管理器

        ViewGroup容器控制其子组件的分布依赖于ViewGroup.LayoutParamsViewGroup.MarginLayoutParams两个内部类。这两个内部类中都提供了一些XML属性, ViewGroup容器中的子组件可以指定这些XML属性。

        表2.2显示了ViewGroup.LayoutParams所支持的两个XML属性。

XML属性说明
android:layout_ height指定该子组件的布局高度
android:layout_ width指定该子组件的布局宽度

android: layout_ height、 android: layout_ width两个 属性支持如下2个属性值。

  • ➢match_ parent(早期叫fill_ parent): 指定子组件的高度、宽度与父容器组件的高度、宽度相同(实际上还要减去填充的空白距离)。
  • ➢wrap_ content: 指定子组件的大小恰好能包裹它的内容即可。

        读者可能对布局高度与布局宽度感到疑惑:为组件指定了高度与宽度不就够了吗?为何还要设置布局高度与布局宽度呢?这是由Android的布局机制决定的,Android组件的大小不仅受它实际的宽度、高度控制,还受它的布局高度与布局宽度控制比如设置一个组件的宽度为30pt,如果将它的布局宽度设为match_ parent, 那么该组件的宽度将会被“拉宽"到占满它所在的父容器;如果将它的布局宽度设为wrap_ content, 那么该组件的宽度才会是30pt。

        ViewGroup.MarginLayoutParams用于控制子组件周围的页边距(Margin, 也就是组件四周的留白),它支持的XML属性如下表所示。

XML属性相关方法说明
android:layout_marginsetMargins(int,int,int,int)指定该子组件四周的页面边距
android:layout_marginBottomsetMargins(int,int,int,int)指定该子组件下边的页面边距
android:layout_marginEndsetMargins(int,int,int,int)指定该子组件结尾处的页面边距
android:layout_marginHorizontalsetMargins(int,int,int,int)指定该子组件左、右两边的页面边距
android:layout_marginLeftsetMargins(int,int,int,int)指定该子组件左边的页面边距
android:layout_marginRightsetMargins(int,int,int,int)指定该子组件右边的页面边距
android:layout_marginStartsetMargins(int,int,int,int)指定该子组件起始处的页面边距
android:layout_marginTopsetMargins(int,int,int,int)指定该子组件上边的页面边距
android:layout_marginVerticalsetMargins(int,int,int,int)指定该子组件上、下两边的页面边距

后面我们还会详细介绍ViewGroup各子类的用法,此处不再详述。

  2.使用XML布局文件控制UI界面

        Android推荐使用XML布局文件来控制视图,这样不仅简单、明了,而且可以将应用的视图控制逻辑从Java或Kotlin代码中分离出来,放入XML文件中控制,从而更好地体现MVC原则

什么是MVC原则:

对于MVC中三者的划分并没有十分明晰的定义和界线,只是一种指导思想,让你按照model,view,controller三个方面来描述你的应用,并通过这三者的的交互,使应用功能得以正常运转。

1 View的职责

其中,View部分比较明确,就是负责显示一切与显示界面无关的东西,都不应该出现在view里面。因此,view中一般不会出现复杂的判断语句,不会出现复杂的运算过程。对于PHP的Web应用而言,毫无疑问,html是view中的主要内容。如下是关于view的几个原则:

  1. 负责显示界面,以HTML为主;
  2. 一般没有复杂的判断语句或运算过程,可以有简单的循环语句、格式化语句。比如,博客首页的文字列表就是一种循环;
  3. 从不调用Model的写方法。也就是说,View只从Model中获取数据,而从不改写Model,所以我们说他们是老死不相往来的。
  4. 一般没有任何准备数据处理的内容,如查询数据库等。这些一般是放在Controller里面,并以变量的形式传给视图。也就是说,视图里面要用到的数据,就是一个变量。

2 Model的职责

对于Model而言,最主要就是保存事物的信息,保证事物的行为和对他可以进行操作。比如,Post类必然有一个用于保存博客文章标题的title属性,必然有一个删除的操作,这都是Model的内容。以下是关于Model的几个原则:

  1. 数据、行为、方法是Model的主要内容;
  2. 实际工作中,Model是MVC中代码量最大,逻辑最复杂的地方,因为关于应用的业务逻辑也要在这里表示;
  3. 注意与Controller区分开。Model是处理业务方面的逻辑,Controller只是简单的协调Model和View之间的关系。只要是与业务有关的,就该放在Model里面。好的设计,应该是胖Model,瘦Controller;

3 Controller的职责

对于Controller,主要是响应用户请求,决定使用什么视图,需要准备什么数据用来显示。以下是有关Controller的设计原则:

  1. 用于处理用户请求,因此,对于request的访问代码应该放在Controller里面,比如$_GET$_POST等。但仅限于获取用户请求数据,不应该对数据有任何操作或预处理,这应该放在model里面。
  2. 调用model类的方法,对model进行写操作。
  3. 调用视图渲染函数,形成对用户request的response。
  4. 一般不要有html代码等其他表现层的东西,这应该是属于view的内容。

        当我们在Android应用的\res\layout目录下定义一个主文件名任意的XML布局文件之后(R.java会自动收录该布局资源),Java或Kotlin代码可通过如下方法在Activity中显示该视图.

setContentView(R.layout.<资源文件名>);

        当在布局文件中添加多个UI组件时,都可以为该UI组件指定android:id属性,该属性的属性值代表该组件的唯一标识

findViewById(R.id.<android.id属性值>);

        一旦在程序中获得指定UI组件之后,接下来就可以通过代码来控制各UI组件的外观行为了,包括为UI组件绑定事件监听器等。

  3.在代码中控制UI界面

        虽然Android推荐使用XML布局文件来控制UI界面,但如果开发者愿意, Android允许开发者像开发Swing应用一样,完全抛弃XML布局文件,完全在Java或kotlin代码中控制UI界面。如果希望在代码中控制UI界面,那么所有的UI组件都将通过new关键字创建出来,然后以合适的方式“搭建”在一起即可。

        从上面程序的粗体字代码可以看出,该程序中所用到的UI组件都是通过new关键字创建出来的,然后程序使用LinearLayout容器来“盛装”这些UI组件,这样就组成了图形用户界面。

提示:

        上面程序代码使用了 Java 8 Lambda 表达式而Android 3.2 默认不支持Lambda 表达式,为了在Android项目中使用Lambda 表达式,程序在codeveiw 模块的build.gradle文件的android 属性中增加了如下配置。

compileOptions{
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

        从上面的程序代码中可以看出,无论创建哪种Ul组件,都需要传入一个this参数,这是由于创建UI组件时传入一个Context参数Context代表访问Android应用环境的全局信息的APl。让UI组件持有一个Context参数,可以让这些UI组件通过该Context参数来获取Android应用环境的全局信息。

        Context本身是一个抽象类,Android应用的Activity、Service都继承了Context,因此Activity 、Service都可直接作为Context使用。

        从上面的程序代码中不难看出,完全在代码中控制UI界面不仅不利于高层次的解耦,而且由于自行创建UI组件,需要调用方法来设置UI组件的行为,因此代码也显得十分臃肿;相反,如果通过XML布局文件来控制UI界面,开发者只要在XML布局文件中使用标签即可创建UI组件,而且只要配置简单的属性即可控制UI组件的行为,因此要简单得多。

        虽然Android应用完全允许开发者像开发Swing应用一样在代码中控制UI界面,但这种方式不仅编程烦琐,而且不利于高层次的解耦,因此不推荐开发者使用这种方式。

  4.使用XML布局文件和Java代码混合控制UI界面

        前面已经提到,完全使用Java代码来控制UI界面不仅烦琐,而且不利于解耦;而完全利用XML布局文件来控制U|界面虽然方便、便捷,但难免有失灵活。因此有些时候,可能需要混合使用XML布局文件和代码来控制UI界面。

        当混合使用XML布局文件和代码来控制UI界面时,习惯上把变化小、行为比较固定的组件放在XML布局文件中管理,而那些变化较多、行为控制比较复杂的组件则交给Java代码来管理。这里就不多赘述了,看代码就好。

实例:简单的图形浏览

    XML文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/picture"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".text_1">
</LinearLayout>

    Java文件

public class text_1 extends AppCompatActivity {

    //定义一个访问图片的数组
    private int[] images = new int[]{R.drawable.view1,
            R.drawable.view2,R.drawable.view3,
            R.drawable.view4,R.drawable.view5};
    private int currentImg = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_text_1);
        //获取LinearLayout布局容器
        LinearLayout main = findViewById(R.id.picture);
        //程序创建ImageView组件
        ImageView image = new ImageView(this);
        //将ImageView组件添加到LinearLayout布局容器中
        main.addView(image);
        //初始化第一张图片
        image.setImageResource(images[0]);
        image.setOnClickListener(v->{
            //注意轮播的细节
            image.setImageResource(images[++currentImg % images.length]);
        });
    }
}

提示:

实现轮播使用: ++currentImg % images.length 来确定位置。

  5.开发自定义View

        前面已经提到,View组件的作用类似于Swing编程中的JPanel,它只是一个矩形的空白区域,View组件没有任何内容。对于Android应用的其他UI组件来说,它们都继承了View组件,然后在View组件提供的空白区域上绘制外观。

        基于Android UI组件的实现原理,开发者完全可以开发出项目定制的组件——当Android系统提供的UI组件不足以满足项目需要时,开发者可以通过继承View来派生自定义组件。

        当开发者打算派生自己的UI组件时,首先定义一个继承View基类的子类,然后重写View类的一个或多个方法。通常可以被用户重写的方法如下。

  • 构造器:重写构造器是定制View的最基本方式,当Java代码创建一个View实例,或根据XML布局文件加载并构建界面时将需要调用该构造器。
  •  onFinishInflate () ∶这是一个回调方法,当应用从XML布局文件加载该组件并利用它来构建界面之后,该方法将会被回调。
  • onMeasure (int,int):调用该方法来检测View组件及其所包含的所有子组件的大小
  • onLayout (boolean,int,int,int,int) :当该组件需要分配其子组件的位置、大小时,该方法就会被回调
  • onSizeChanged (int,int,int,int) :当该组件的大小被改变时回调该方法
  • onDraw (Canvas):当该组件将要绘制它的内容时回调该方法进行绘制。
  • onKeyDown (int,KeyEvent) :当某个键被按下时触发该方法。
  • onKeyUp (int,KeyEvent) :当松开某个键时触发该方法。
  • onTrackballEvent(MotionEvent) :当发生轨迹球事件时触发该方法。
  • onTouchEvent (MotionEvent) :当发生触摸屏事件时触发该方法。
  • onFocusChanged (boolean gainFocus, int direction, RectpreviouslyFocusedRect) :当该组件焦点发生改变时触发该方法。
  • onWindowFocusChanged (boolean):当包含该组件的窗口失去或得到焦点时触发该方法
  • onAttachedToWindow ()︰当把该组件放入某个窗口时触发该方法。
  • onDetachedFromWindow () ︰当把该组件从某个窗口上分离时触发该方法。
  • onWindowVisibilityChanged (int) :当包含该组件的窗口的可见性发生改变时触发该方法

        当需要开发自定义View时,开发者并不需要重写上面列出的所有方法,而是可以根据业务需要重写上面的部分方法。例如,下面的示例程序就只重写onDraw (Canvas)方法。

        此外,如果要新建的自定义组件只是组合现有组件,不需要重新绘制所有的组件内容,那么就更简单了——只要实现自定义组件的构造器,在自定义构造器中使用LayoutInflater加载布局文件即可。

实例:跟随手指或鼠标的小球

        首先自定义组件:DrawView.java

public class DrawView extends View {
    private float currentX = 40f;
    private float currentY = 50f;
    //定义并创建画笔
    private Paint p=new Paint();


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

    public DrawView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //设置画笔的颜色
        p.setColor(Color.RED);
        //绘制一个小圆点
        canvas.drawCircle(currentX,currentY,15F,p);
    }
    //触碰事件重写事件处理方法

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //修改位置变量
        currentX = event.getX();
        currentY = event.getY();
        //通知当前组件重绘自己
        invalidate();
        //返回true表明该处理方法已经处理该事件
        return true;
    }
}

        上面的DrawView组件继承了View基类,并重写了onDraw方法——该方法负责在该组件的指定位置绘制一个小球。除此之外,该组件还重写了onTouchEvent (MotionEventevent)方法,该方法用于处理该组件的触碰事件,当用户手指触碰该组件时将会激发该方法。当手指在触摸屏上移动时,将会不断地触发触摸屏事件,事件监听器中负责触发事件的坐标将被传入DrawView组件,并通知该组件重绘——这样即可保证DrawView上小球跟随手指移动而移动。
 

    XML文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent"
    tools:context=".text_2">

    <com.example.text_one.DrawView
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

    Java文件(没有任何编写)

public class text_2 extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_text_2);
    }
}

散称知识点:

 对于每个Android开发者而言,Android提供的官方文档是必看的。下面简单介绍读者应该如何查看Android文档——实际上是一种学习方法。

在第1章在线安装Android SDK组件时,通过图1.12所示窗口选择Android工具时勾选 "Documentation for Android SDK"项,就会将Android文档安装到本地磁盘。一旦我们将Android文档安装到本地磁盘,就可以在Android SDK安装目录下找到docs子目录,打开docs子目录下的index.html页面,并单击该页面上方的“Develop”→“APIGuides”(开发指南)标签页。用户将看到如图2.2所示的页面。

        图2.2所示就是Android官方提供的开发指南文档,这份文档也是笔者当初学习、开发Android应用的重要文档。

提示:

        如果具有良好的英文阅读能力,而且Java基本功扎实,学习Android完全可以不用购买任何图书,直接阅读这份API Guides也是很好的学习方法。

 Drawable是Android提供的一个抽象基类,它代表了“可以被绘制出来的某种东西”,Drawable包括了大量子类,比如BitmapDrawable代表位图  Drawable、ColorDrawable代表颜色Drawable、ShapeDrawable代表 几何形状Drawable各种Drawable可于定制UI组件的背景等外观。本书第7章会详细介绍各种Drawable的功能与用法。
 

 实际上,选择哪种 Activity 只是告诉AS采用不同的 Activity 模板,但最终还是需要开发者自己修改配置文件和Java代码的为同一个应用选择不同的模板只会影响所需要修改的代码但是最后达到的效果是相同的一般选择添加 Empty Activity ,并使用Java作为源代码。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

撩得Android一次心动

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值