Android自定义View实现很简单

继承View,重写构造函数、onDraw,(onMeasure)等函数。

如果自定义的View需要有自定义的属性,需要在values下建立attrs.xml。在其中定义你的属性。

在使用到自定义View的xml布局文件中需要加入xmlns:前缀="http://schemas.android.com/apk/res/你的应用所在的包路径".

在使用自定义属性的时候,使用前缀:属性名,如my:textColor="#FFFFFFF"。

实例:

package demo.view.my;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Paint.Style;import android.util.AttributeSet;import android.view.View;/** * 这个是自定义的TextView. * 至少需要重载构造方法和onDraw方法 * 对于自定义的View如果没有自己独特的属性,可以直接在xml文件中使用就可以了 * 如果含有自己独特的属性,那么就需要在构造函数中获取属性文件attrs.xml中自定义属性的名称 * 并根据需要设定默认值,放在在xml文件中没有定义。 * 如果使用自定义属性,那么在应用xml文件中需要加上新的schemas, * 比如这里是xmlns:my="http://schemas.android.com/apk/res/demo.view.my" * 其中xmlns后的“my”是自定义的属性的前缀,res后的是我们应用所在的包 * @author Administrator * */public class MyView extends View {        Paint mPaint; //画笔,包含了画几何图形、文本等的样式和颜色信息    public MyView(Context context) {        super(context);            }        public MyView(Context context, AttributeSet attrs){        super(context, attrs);        mPaint = new Paint();        //TypedArray是一个用来存放由context.obtainStyledAttributes获得的属性的数组        //在使用完成后,一定要调用recycle方法        //属性的名称是styleable中的名称+“_”+属性名称        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MyView);        int textColor = array.getColor(R.styleable.MyView_textColor, 0XFF00FF00); //提供默认值,放置未指定        float textSize = array.getDimension(R.styleable.MyView_textSize, 36);        mPaint.setColor(textColor);        mPaint.setTextSize(textSize);                array.recycle(); //一定要调用,否则这次的设定会对下次的使用造成影响    }        public void onDraw(Canvas canvas){        super.onDraw(canvas);        //Canvas中含有很多画图的接口,利用这些接口,我们可以画出我们想要的图形        //mPaint = new Paint();        //mPaint.setColor(Color.RED);        mPaint.setStyle(Style.FILL); //设置填充        canvas.drawRect(10, 10, 100, 100, mPaint); //绘制矩形                mPaint.setColor(Color.BLUE);        canvas.drawText("我是被画出来的", 10, 120, mPaint);    }}

相应的属性文件:

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="MyView">        <attr name="textColor" format="color"/>        <attr name="textSize" format="dimension"/>    </declare-styleable></resources>

在布局文件中的使用:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"               xmlns:my="http://schemas.android.com/apk/res/demo.view.my"     android:orientation="vertical"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    >        <demo.view.my.MyView        android:layout_width="fill_parent"        android:layout_height="wrap_content"         my:textColor="#FFFFFFFF"         my:textSize="22dp"        /></LinearLayout>

注意事项:

做Android布局是件很享受的事,这得益于他良好的xml方式。使用xml可以快速 有效的为软件定义界面。可是有时候我们总感觉官方定义的一些基本组件不够用,自定义组件就不可避免了。那么如何才能做到像官方提供的那些组件一样用xml 来定义他的属性呢?现在我们就来讨论一下他的用法。

一、在res/values文件下定义一个attrs.xml文件,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ToolBar">
<attr name="buttonNum" format="integer"/>
<attr name="itemBackground" format="reference|color"/>
</declare-styleable>
</resources>

二、在布局xml中如下使用该属性:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:toolbar="http://schemas.android.com/apk/res/cn.zzm.toolbar"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<cn.zzm.toolbar.ToolBar android:id="@+id/gridview_toolbar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@drawable/control_bar"
android:gravity="center"
toolbar:buttonNum="5"
toolbar:itemBackground="@drawable/control_bar_item_bg"/>
</RelativeLayout>

三、在自定义组件中,可以如下获得xml中定义的值:

TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.ToolBar);
buttonNum = a.getInt(R.styleable.ToolBar_buttonNum, 5);
itemBg = a.getResourceId(R.styleable.ToolBar_itemBackground, -1);

a.recycle();

就这么简单的三步,即可完成对自定义属性的使用。

*********************************************************************

好了,基本用法已经讲完了,现在来看看一些注意点和知识点吧。

首先来看看attrs.xml文件。

该文件是定义属性名和格式的地方,需要用<declare-styleable name="ToolBar"></declare-styleable>包围所有属性。其中name为该属性集的名字,主要用途是标 识该属性集。那在什么地方会用到呢?主要是在第三步。看到没?在获取某属性标识时,用 到"R.styleable.ToolBar_buttonNum",很显然,他在每个属性前面都加了"ToolBar_"。

在来看看各种属性都有些什么类型吧:string , integer , dimension , reference , color , enum.

前面几种的声明方式都是一致的,例如:<attr name="buttonNum" format="integer"/>。
只有enum是不同的,用法举例:

<attr name="testEnum">
<enum name="fill_parent" value="-1"/>
<enum name="wrap_content" value="-2"/>
</attr>

如果该属性可同时传两种不同的属性,则可以用“|”分割开即可。

让我们再来看看布局xml中需要注意的事项。

首先得声明一下:xmlns:toolbar=http://schemas.android.com/apk/res/cn.zzm.toolbar
注意,“toolbar”可以换成其他的任何名字,后面的url地址必须最后一部分必须用上自定义组件的包名。自定义属性了,在属性名前加上“toolbar”即可。

最后来看看java代码中的注意事项。

在自定义组件的构造函数中,用

TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.ToolBar);

来获得对属性集的引用,然后就可以用“a”的各种方法来获取相应的属性值了。这里需要注意的是,如果使用的方法和获取值的类型不对的话,则会返回默 认值。因此,如果一个属性是带两个及以上不用类型的属性,需要做多次判断,知道读取完毕后才能判断应该赋予何值。当然,在取完值的时候别忘了回收资源哦!

属性详解:

1. reference:参考某一资源ID。   (1)属性定义:   <declare-styleable name = "名称">  <attr name = "background" format = "reference" />  </declare-styleable>  (2)属性使用:   <ImageView  android:layout_width = "42dip" android:layout_height = "42dip"  android:background= "@drawable/图片ID"  />  2. color:颜色值。  (1)属性定义:   <declare-styleable name = "名称">  <attr name = "textColor" format = "color" />  </declare-styleable>   (2)属性使用:   <TextView  android:layout_width = "42dip" android:layout_height = "42dip"  android:textColor= "#00FF00"  />  3. boolean:布尔值。   (1)属性定义:   <declare-styleable name = "名称">  <attr name = "focusable" format = "boolean" />  </declare-styleable>  (2)属性使用:   <Button  android:layout_width = "42dip"  android:layout_height = "42dip"  android:focusable= "true"  />  4. dimension:尺寸值。   (1)属性定义:   <declare-styleable name = "名称">  <attr name = "layout_width" format = "dimension" />  </declare-styleable>  (2)属性使用:   <Button  android:layout_width= "42dip"  android:layout_height= "42dip"  />  5. float:浮点值。   (1)属性定义:   <declare-styleable name = "AlphaAnimation">  <attr name = "fromAlpha" format = "float" />  <attr name = "toAlpha" format = "float" />  </declare-styleable>  (2)属性使用:   <alpha  android:fromAlpha= "1.0"  android:toAlpha= "0.7"  />  6. integer:整型值。   (1)属性定义:   <declare-styleable name = "AnimatedRotateDrawable">  <attr name = "visible" />  <attr name = "frameDuration" format="integer" />  <attr name = "framesCount" format="integer" />  <attr name = "pivotX" />  <attr name = "pivotY" />  <attr name = "drawable" />  </declare-styleable>  (2)属性使用:   <animated-rotate  xmlns:android = "http://schemas.android.com/apk/res/android"  android:drawable = "@drawable/图片ID"   android:pivotX = "50%"  android:pivotY = "50%"  android:framesCount= "12"  android:frameDuration= "100" />  7. string:字符串。   (1)属性定义:   <declare-styleable name = "MapView">  <attr name = "apiKey" format = "string" /> </declare-styleable>  (2)属性使用:   <com.google.android.maps.MapView  android:layout_width = "fill_parent" android:layout_height = "fill_parent" android:apiKey= "0jOkQ80oD1JL9C6HAja99uGXCRiS2CGjKO_bc_g"  />  8. fraction:百分数。   (1)属性定义:   <declare-styleable name="RotateDrawable">  <attr name = "visible" />  <attr name = "fromDegrees" format = "float" />  <attr name = "toDegrees" format = "float" />  <attr name = "pivotX" format = "fraction" />  <attr name = "pivotY" format = "fraction" />  <attr name = "drawable" /> </declare-styleable>  (2)属性使用:   <rotate  xmlns:android = "http://schemas.android.com/apk/res/android"    android:interpolator = "@anim/动画ID"  android:fromDegrees = "0"    android:toDegrees = "360"  android:pivotX= "200%"  android:pivotY= "300%"    android:duration = "5000"  android:repeatMode = "restart" android:repeatCount = "infinite"  />  9. enum:枚举值。   (1)属性定义:   <declare-styleable name="名称">  <attr name="orientation">  <enumname="horizontal" value="0" /> <enumname="vertical" value="1" /> </attr>  </declare-styleable>  (2)属性使用:  <LinearLayout  xmlns:android = "http://schemas.android.com/apk/res/android"  android:orientation= "vertical"  android:layout_width = "fill_parent"  android:layout_height = "fill_parent"  > </LinearLayout>  10. flag:位或运算。   (1)属性定义:   <declare-styleable name="名称">  <attr name="windowSoftInputMode">  <flagname = "stateUnspecified" value = "0" />  <flagname = "stateUnchanged" value = "1" />  <flagname = "stateHidden" value = "2" />  <flagname ="stateAlwaysHidden" value = "3" />  <flagname = "stateVisible" value = "4" />  <flagname = "stateAlwaysVisible" value = "5" />  <flagname = "adjustUnspecified" value = "0x00" />  <flagname = "adjustResize" value = "0x10" />  <flagname = "adjustPan" value = "0x20" />  <flagname = "adjustNothing" value = "0x30" />  </attr>  </declare-styleable>   (2)属性使用:  <activity  android:name = ".StyleAndThemeActivity"  android:label = "@string/app_name"  android:windowSoftInputMode= "stateUnspecified | stateUnchanged | stateHidden"> <intent-filter>  <action android:name = "android.intent.action.MAIN" />  <category android:name = "android.intent.category.LAUNCHER" />  </intent-filter>  </activity>  注意:  属性定义时可以指定多种类型值。   (1)属性定义:   <declare-styleable name = "名称">  <attr name = "background" format = "reference|color" />  </declare-styleable>  (2)属性使用:   <ImageView  android:layout_width = "42dip" android:layout_height = "42dip"  android:background= "@drawable/图片ID|#00FF00"  />
自定义组合控件:
第一个实现一个带图片和文字的按钮,如图所示:

    

整个过程可以分四步走。第一步,定义一个layout,实现按钮内部的布局。代码如下:

    <?xml version="1.0" encoding="utf-8"?>      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"          android:orientation="horizontal"          android:layout_width="fill_parent"          android:layout_height="fill_parent"          >      <ImageView          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:id="@+id/iv"          android:src="@drawable/confirm"          android:paddingTop="5dip"          android:paddingBottom="5dip"          android:paddingLeft="40dip"          android:layout_gravity="center_vertical"          />      <TextView          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:text="确定"          android:textColor="#000000"          android:id="@+id/tv"          android:layout_marginLeft="8dip"          android:layout_gravity="center_vertical"          />      </LinearLayout>  

这个xml实现一个左图右字的布局,接下来写一个类继承LinearLayout,导入刚刚的布局,并且设置需要的方法,从而使的能在代码中控制这个自定义控件内容的显示。代码如下:

package com.notice.ib;import android.content.Context;import android.util.AttributeSet;import android.view.LayoutInflater;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.TextView;public class ImageBt extends LinearLayout {    private ImageView iv;    private TextView  tv;    public ImageBt(Context context) {        this(context, null);    }    public ImageBt(Context context, AttributeSet attrs) {        super(context, attrs);        // 导入布局        LayoutInflater.from(context).inflate(R.layout.custombt, this, true);        iv = (ImageView) findViewById(R.id.iv);        tv = (TextView) findViewById(R.id.tv);    }    /**     * 设置图片资源     */    public void setImageResource(int resId) {        iv.setImageResource(resId);    }    /**     * 设置显示的文字     */    public void setTextViewText(String text) {        tv.setText(text);    }}

第三步,在需要使用这个自定义控件的layout中加入这控件,只需要在xml中加入即可。方法如下:

<RelativeLayout         android:orientation="horizontal"         android:layout_width="fill_parent"         android:layout_height="wrap_content"         android:layout_gravity="bottom"         >         <com.notice.ib.ImageBt             android:id="@+id/bt_confirm"             android:layout_height="wrap_content"             android:layout_width="wrap_content"             android:layout_alignParentBottom="true"             android:background="@drawable/btbg"             android:clickable="true"             android:focusable="true"             />         <com.notice.ib.ImageBt             android:id="@+id/bt_cancel"             android:layout_toRightOf="@id/bt_confirm"             android:layout_height="wrap_content"             android:layout_width="wrap_content"             android:layout_alignParentBottom="true"             android:background="@drawable/btbg"             android:clickable="true"             android:focusable="true"            />         </RelativeLayout>

注意的是,控件标签使用完整的类名即可。为了给按钮一个点击效果,你需要给他一个selector背景,这里就不说了。

最后一步,即在activity中设置该控件的内容。当然,在xml中也可以设置,但是只能设置一个,当我们需要两次使用这样的控件,并且显示内容 不同时就不行了。在activity中设置也非常简单,我们在ImageBt这个类中已经写好了相应的方法,简单调用即可。代码如下:

public class MainActivity extends Activity {    private ImageBt ib1;    private ImageBt ib2;    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.login);        ib1 = (ImageBt) findViewById(R.id.bt_confirm);        ib2 = (ImageBt) findViewById(R.id.bt_cancel);        ib1.setTextViewText("确定");        ib1.setImageResource(R.drawable.confirm);        ib2.setTextViewText("取消");        ib2.setImageResource(R.drawable.cancel);        ib1.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                    //在这里可以实现点击事件            }        });    }}

这样,一个带文字和图片的组合按钮控件就完成了。这样梳理一下,使用还是非常简单的。组合控件能做的事还非常多,主要是在类似上例中的ImageBt类中写好要使用的方法即可。

再来看一个组合控件,带删除按钮的EidtText。即在用户输入后,会出现删除按钮,点击即可取消用户输入。

定义方法和上例一样。首先写一个自定义控件的布局:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    ><EditText    android:id="@+id/et"    android:layout_width="fill_parent"    android:layout_height="wrap_content"    android:singleLine="true"    /><ImageButton    android:id="@+id/ib"    android:visibility="gone"    android:src="@drawable/menu_delete"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:background="#00000000"    android:layout_alignRight="@+id/et" /></RelativeLayout>

实现输入框右侧带按钮效果,注意将按钮隐藏。然后写一个EditCancel类,实现删除用户输入功能。这里用到了TextWatch这个接口,监听输入框中的文字变化。使用也很简单,实现他的三个方法即可。看代码:

package com.notice.ce;import android.content.Context;import android.text.Editable;import android.text.TextWatcher;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.View;import android.widget.EditText;import android.widget.ImageButton;import android.widget.LinearLayout;public class EditCancel extends LinearLayout implements EdtInterface {    ImageButton ib;    EditText    et;    public EditCancel(Context context) {        super(context);    }    public EditCancel(Context context, AttributeSet attrs) {        super(context, attrs);        LayoutInflater.from(context).inflate(R.layout.custom_editview, this, true);        init();    }    private void init() {        ib = (ImageButton) findViewById(R.id.ib);        et = (EditText) findViewById(R.id.et);        et.addTextChangedListener(tw);// 为输入框绑定一个监听文字变化的监听器        // 添加按钮点击事件        ib.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View v) {                hideBtn();// 隐藏按钮                et.setText("");// 设置输入框内容为空            }        });    }    // 当输入框状态改变时,会调用相应的方法    TextWatcher tw = new TextWatcher() {                       @Override                       public void onTextChanged(CharSequence s, int start, int before, int count) {                           // TODO Auto-generated method stub                       }                       @Override                       public void beforeTextChanged(CharSequence s, int start, int count, int after) {                           // TODO Auto-generated method stub                       }                       // 在文字改变后调用                       @Override                       public void afterTextChanged(Editable s) {                           if (s.length() == 0) {                               hideBtn();// 隐藏按钮                           } else {                               showBtn();// 显示按钮                           }                       }                   };    @Override    public void hideBtn() {        // 设置按钮不可见        if (ib.isShown()) ib.setVisibility(View.GONE);    }    @Override    public void showBtn() {        // 设置按钮可见        if (!ib.isShown()) ib.setVisibility(View.VISIBLE);    }}interface EdtInterface {    public void hideBtn();    public void showBtn();}

在TextWatch接口的afterTextChanged方法中对文字进行判断,若长度为0,就隐藏按钮,否则,显示按钮。

另外,实现ImageButton(即那个叉)的点击事件,删除输入框中的内容,并隐藏按钮。

后面两步的实现就是加入到实际布局中,就不再写出来了,和上例的步骤一样的。最后显示效果如图:

学会灵活的使用组合控件,对UI开发会有很大帮助。

Android 自定义控件外观

首先我们看下系统的RadioButton:
RadioButton长成什么样子是由其Background、Button等属性决定的,Android系统
使用style定义了默认的属性,在android源码
android/frameworks/base/core/res/res/values/styles.xml中可以看到默认的定义:

<style name="Widget.CompoundButton.RadioButton">        <item name="android:background">@android:drawable/btn_radio_label_background</item>        <item name="android:button">@android:drawable/btn_radio</item></style>

即其背景图是btn_radio_label_background,其button的样子是btn_radio

btn_radio_label_background是什么?
其路径是android/frameworks/base/core/res/res/drawable-mdpi/btn_radio_label_background.9.png
可以看到是一个NinePatch图片,用来做背景,可以拉伸填充。

btn_radio是什么?
其路径是android/frameworks/base/core/res/res/drawable/btn_radio.xml
是个xml定义的drawable,打开看其内容:

<selector xmlns:android="http://schemas.android.com/apk/res/android">        <item android:state_checked="true" android:state_window_focused="false"          android:drawable="@drawable/btn_radio_on" />    <item android:state_checked="false" android:state_window_focused="false"          android:drawable="@drawable/btn_radio_off" />    <item android:state_checked="true" android:state_pressed="true"          android:drawable="@drawable/btn_radio_on_pressed" />    <item android:state_checked="false" android:state_pressed="true"          android:drawable="@drawable/btn_radio_off_pressed" />    <item android:state_checked="true" android:state_focused="true"          android:drawable="@drawable/btn_radio_on_selected" />    <item android:state_checked="false" android:state_focused="true"          android:drawable="@drawable/btn_radio_off_selected" />    <item android:state_checked="false" android:drawable="@drawable/btn_radio_off" />    <item android:state_checked="true" android:drawable="@drawable/btn_radio_on" /></selector>

定义了不同状态下radioButton长成什么样子。
如果不知道selector是什么,就要去看下Android SDK文档中Dev Guide->Application Resources->Resource Types。
以下面一个item为例:
<item android:state_checked="true" android:state_pressed="true"
android:drawable="@drawable/btn_radio_on_pressed" />
意思即为当radiobutton被选中时,并且被按下时,其Button应该长成btn_radio_on_pressed这个样子。

文件是android/frameworks/base/core/res/res/drawable-mdpi/btn_radio_on_pressed.png

drawable的item中可以有以下属性:
android:drawable="@[package:]drawable/drawable_resource"
android:state_pressed=["true" | "false"]
android:state_focused=["true" | "false"]
android:state_selected=["true" | "false"]
android:state_active=["true" | "false"]
android:state_checkable=["true" | "false"]
android:state_checked=["true" | "false"]
android:state_enabled=["true" | "false"]
android:state_window_focused=["true" | "false"]
当按钮的状态和某个item匹配后,就会使用此item定义的drawable作为按钮图片。

从上面分析我们如果要修改RadioButton的外观,那么步骤应该是:
(1)制作一个9patch的图片作为背景图
准备一副PNG图片,其中白色为透明色,是否需要透明各人根据自己需要决定。

运行SDK/tools/draw9patch
在可伸缩的范围周围加上黑色的线告知系统这些区域可以伸缩。
制作完的图片,周围多了黑色线。

(2)针对不同的状态提供按钮图片
enabled, on: 紫色外框、红色中心点

enabled, off:只有紫色外框

enabled, on, pressed:黄色外框,红色中心点

enabled, off, pressed:黄色外框

disabled, on: 灰色外框、灰色中心点

disabled, off: 灰色外框

其余的状态此处就不再定义。
(3)使用xml描述一个drawable
在res/drawable/创建custom_radio_btn.xml

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android">    <item android:state_enabled="true" android:state_checked="true" android:state_pressed="true"          android:drawable="@drawable/enabled_on_pressed" />              <item android:state_enabled="true" android:state_checked="false" android:state_pressed="true"          android:drawable="@drawable/enabled_off_pressed" />    <item android:state_enabled="true" android:state_checked="true"          android:drawable="@drawable/enabled_on" />              <item android:state_enabled="true" android:state_checked="false"          android:drawable="@drawable/enabled_off" />              <item android:state_enabled="false" android:state_checked="true"          android:drawable="@drawable/disabled_on" />              <item android:state_enabled="false" android:state_checked="false"          android:drawable="@drawable/disabled_off" />              </selector>

Item顺序是有讲究的,条件限定越细致,则应该放到前面。比如这儿如果把1,2行和3,4行的item交换,那么pressed的就永远无法触发了,因为有item已经满足条件返回了。可以理解为代码中的if语句。
(4)创建一个自定义的style,并应用到RaidioButton的style属性上

<style name="CustomRadioBtn">        <item name="android:background">@drawable/radio_btn_bg</item>        <item name="android:button">@drawable/custom_radio_btn</item></style>

运行ap即可看到此RadioButton的外观已经改变,此demo可以看到文字被按钮遮盖了一部分,
这儿是因第一步制作9patch图片时没有留出按钮图片空间来,稍作修改即可。

更多相关文章

  1. Android(安卓)Layout机制研究
  2. Android加密之文件级加密
  3. Android(安卓)内存管理
  4. android应用安全——通信安全(android https)
  5. Android(安卓)Studio项目中使用 AndroidX支持库的相关配置说明
  6. Android(安卓)Theme主题样式开发注意点
  7. 箭头函数的基础使用
  8. NPM 和webpack 的基础使用
  9. Python list sort方法的具体使用

随机推荐

  1. Android(安卓)RemoteCallbackList类
  2. Android(安卓)Material Design-Creating
  3. 博文目录 | 杰瑞教育原创系列文章目录一
  4. 如何在Android模拟器上安装apk文件
  5. Android学习笔记——网络技术
  6. AndroidKotLin系列--Android(安卓)Studio
  7. Android--SQLite数据库应用技巧分享
  8. Android(安卓)应用跳转到指定QQ临时聊天
  9. Android(安卓)各种杀脑细胞的问题集合
  10. Android(安卓)传统蓝牙配对连接断开 附de