Android(一) 入门


 Android知识体系图

安卓架构

 

 华为手机真机连接

运行平台和测试环境

官方开发IDE:Android Studio,基于Intellij平台,自带JDK。

手机上运行APP

设置--------->关于手机------------>连续点击 版本号 选项,会提示“已经进入开发者模式”

------------->找到开发人员选项---------->打开 USB调试 选项----------->华为手机,一并将“'仅充电'模式下允许ADB调试”选项开关打开。这样,华为手机usb调试打开后,就不会自动关闭了

下载360手机助手并安装

连接手机,如果连接成功会自动下载安装手机所需驱动

卸载手机助手

速览Android三大核心

AS新建空Activity项目

项目目录

 可以直接运行,运行之后,app目录下会多出一个build文件夹

 现在要关注的是src/main下的三项

  • java底下用来编写代码,如Activity
  • res下面是各种资源,如布局文件
  • AndroidManifest.xml是清单文件

对应下面要说的三大核心

  • Activity
  • 布局
  • 清单文件

Activity

  • MainActivity
  • onCreate()
  • setContentView()

Activity是可视化的界面,打开界面就会加载onCreate()方法,相当于入口方法

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 设置内容视图
        // R:为每个资源文件按类别分配一个索引,使程序员可以通过R.类别名.资源名去操作对应的资源
        setContentView(R.layout.activity_main);
    }
}

R是一个类,自动生成的,有很多内部静态类 ,内部类中有静态属性

 res目录下的资源文件会被扫描,并生成一个资源清单类,因此,你可以通过R.xx.xx来访问res下的资源

 AS3.6后找不到这个R.java,很奇怪

在代码中使用R来访问资源,在XML中则按如下格式访问:

@<资源对应的内部类的类名>/<资源项的名称>

 通过

setContentView(R.layout.activity_main);

将Activity与一个布局文件绑在了一起,或者说加载了一个布局文件。

布局文件

我们发现在res/layout目录下有上面代码绑定的文件 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

androidx.constraintlayout.widget.ConstraintLayout>

 布局里面可以添加控件

清单文件

但有多个布局文件的时候,怎么知道要先加载MainActivity呢?使用清单文件。

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity>
    application>

manifest>

每创建一个activity,Android Studio会自动添加一个配置

intent-filter 意图过滤器

<action android:name="android.intent.action.MAIN" /> 启动程序
<category android:name="android.intent.category.LAUNCHER" /> 在应用列表中形成图标

有上面意图过滤器的Activity是入口Activity 

资源 

一个项目的res目录

 res目录下的资源,sdk会在编译应用时,自动在R.java文件中为这些资源创建索引,程序可直接通过R资源清单类进行访问。

/res/animator/

  • 存放定义属性动画的XML文件

/res/anim/

  • 存放定义补间动画的XML文件

/res/drawable

  • 存放图片文件,可以编译成Drawable对象的XML文件
  • Drawable对象
    • StateListDrawble对象,XML文件根元素为,可以组织多个Drawable对象,根据不同的状态显示不同图片
      • <?xml version="1.0" encoding="utf-8"?>
        <selector xmlns:android="http://schemas.android.com/apk/res/android">
            <item android:state_selected="true" android:drawable="@drawable/tabbar_home_pressed"/>
            <item android:state_pressed="true" android:drawable="@drawable/tabbar_home_pressed"/>
            <item android:drawable="@drawable/tabbar_home"/>
        selector>

        state_后面可以跟: active(激活) checkable(勾选) enabled first focused last middle pressed selected windwon_focused(窗口得到焦点)

  • LayerDrawable
  • ShapeDrawable
  • ClipDrawable
  • AnimationDrawable

/res/layout

  • 布局文件

/res/menu

  • 菜单资源,包括选项菜单、子菜单、上下文菜单
    • <?xml version="1.0" encoding="utf-8"?>
      <menu xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto">
          <item android:title="保存"
              android:id="@+id/save"
              android:icon="@mipmap/ic_launcher"
              app:showAsAction="always|withText"
              />
          <item android:title="设置" android:id="@+id/setting"/>
          <item android:title="更多操作">
              
              <menu>
                  <item android:title="退出" android:id="@+id/exit"/>
                  <item android:title="子菜单2"/>
                  <item android:title="子菜单3"/>
              menu>
          item>
      menu>

/res/values

  • 存放各种简单值的XML文件,包括字符串、整数值、颜色值、数组等。
  • 根元素都是
  • 子元素
    • string/integer/bool
    • color
    • array
    • style
    • dimen
    • ...
  • 不同子元素放在不同文件中
    • arrays.xml
    • colors.xml
    • strings.xml
    • style.xml
    • ...

布局

1、px和dpi

android developer guide,下同)。

偶尔用到px的情况,是需要画1像素表格线或阴影线的时候,用其他单位如dp会显得模糊。

http://blog.csdn.net/qq_22989777/article/details/52936675

显示Intent举例

1、构造方法传入Component

Intent intent = new Intent(this, SecondActivity.class);  
startActivity(intent);  

2、setComponent方法

ComponentName componentName = new ComponentName(this, SecondActivity.class);  
// 或者ComponentName componentName = new ComponentName(this, "com.example.app016.SecondActivity");  
// 或者ComponentName componentName = new ComponentName(this.getPackageName(), "com.example.app016.SecondActivity");  

Intent intent = new Intent();  
intent.setComponent(componentName);  
startActivity(intent);  

3、setClass/setClassName方法

Intent intent = new Intent();  

intent.setClass(this, SecondActivity.class);  
// 或者intent.setClassName(this, "com.example.app016.SecondActivity");  
// 或者intent.setClassName(this.getPackageName(), "com.example.app016.SecondActivity");  

startActivity(intent);  

隐式Intent举例

设置一个Action,

<activity  
    android:name="com.example.app016.SecondActivity">  
    <intent-filter>  
        <action android:name="abcdefg"/>  
        <category android:name="android.intent.category.DEFAULT"/>  
    intent-filter>  
activity> 

然后,在MainActivity中有如下方法设置

1、setAction方法

Intent intent = new Intent();  
intent.setAction("abcdefg");  
startActivity(intent);  

2、构造方法直接设置Action

Intent intent = new Intent("abvdefg");
startActivity(intent);

其他程序可以调用这个Activity只要使用这个Action字符串即可,我们也可以调用其他程序的Action例如:

Intent intent = new Intent(Intent.ACTION_DIAL);  
// 或者Intent intent = new Intent("android.intent.action.DIAL");  
// Intent.ACTION_DIAL是内置常量,值为"android.intent.action.DIAL"  
startActivity(intent);  

我们可以调用拨号界面

3、一个Activity可调用多个Action

如果我们设置的intent-filter中的Action为”ACTION_DIAL”那么在启动该Intent时会自动跳出选择界面,而且一个Activity中可以处理多个Action

<activity  
    android:name="com.example.app016.SecondActivity">  
    <intent-filter>  
          
        <action android:name="com.example.app016.SEND_EMAIL"/>  
        <action android:name="com.example.app016.SEND_MESSAGE"/>  
        <action android:name="com.example.app016.DAIL"/>  
        <category android:name="android.intent.category.DEFAULT" />  
    intent-filter>  
activity> 

如果没有该Activity系统会抛出ActivityNotFoundException异常,我们应该要用try/catch捕获或者也可以使用Intent的resolveActivity方法判断这个Intent是否能找到合适的Activity

Intent intent = new Intent(Intent.ACTION_DIAL);  
if(intent.resolveActivity(getPackageManager()) == null)  
{  
    // 设置控件不可用  
}  

注意resolveActivity方法返回值就是显式Intent上面讲到的ComponentName对象,如果有多个Activity那么返回用户所选择的对象

Intent intent = new Intent(Intent.ACTION_DIAL);  
ComponentName componentName = intent.resolveActivity(getPackageManager());  
if(componentName != null)  
{  
    String className = componentName.getClassName();  
    Toast.makeText(this, className, Toast.LENGTH_SHORT).show();  
}  

参考:

Intent的中文意思是“意图,目的”的意思,可以理解为不同组件之间通信的“媒介”或者“信使”。

目标组件一般要通过Intent来声明自己的条件,一般通过组件中的元素来过滤。

Intent在由以下几个部分组成:动作(action),数据(data),分类(Category),类型(Type),组件(Component),和扩展信息(Extra)。

Intent在寻找目标组件的时候有两种方法:第一,通过组件名称直接指定;第二,通过Intent Filter过滤指定

Intent启动不同组件的方法
组件名称  方法名称
Activity  startActivity()  startActivityForResult()
Service  startService()  bindService()
Broadcasts  sendBroadcast()  sendOrderedBroadcast()  sendStickyBroadcast()


常见的Activity Action Intent常量
常量名称   常量值  意义
ACTION_MAIN  android.intent.action.MAIN   应用程序入口
ACTION_VIEW  android.intent.action.VIEW  显示数据给用户
ACTION_ATTACH_DATA  android.intent.action.ATTACH_DATA  指明附加信息给其他地方的一些数据
ACTION_EDIT  android.intent.action.EDIT  显示可编辑的数据
ACTION_PICK  android.intent.action.PICK  选择数据
ACTION_CHOOSER  android.intent.action.CHOOSER  显示一个Activity选择器
ACTION_GET_CONTENT  android.intent.action.GET_CONTENT  获得内容
ACTION_DIAL  android.intent.action.GET_CONTENT  显示打电话面板
ACITON_CALL  android.intent.action.DIAL  直接打电话
ACTION_SEND  android.intent.action.SEND  直接发短信
ACTION_SENDTO  android.intent.action.SENDTO  选择发短信
ACTION_ANSWER  android.intent.action.ANSWER  应答电话
ACTION_INSERT  android.intent.action.INSERT  插入数据
ACTION_DELETE  android.intent.action.DELETE  删除数据
ACTION_RUN  android.intent.action.RUN  运行数据
ACTION_SYNC  android.intent.action.SYNC  同步数据
ACTION_PICK_ACTIVITY  android.intent.action.PICK_ACTIVITY  选择Activity
ACTION_SEARCH  android.intent.action.SEARCH  搜索
ACTION_WEB_SEARCH  android.intent.action.WEB_SEARCH  Web搜索
ACTION_FACTORY_TEST  android.intent.action.FACTORY_TEST  工厂测试入口点


常见的BroadcastIntent Action常量  BroadcastIntent
Action字符串常量  描述
ACTION_TIME_TICK  系统时间每过一分钟发出的广播
ACTION_TIME_CHANGED  系统时间通过设置发生了变化
ACTION_TIMEZONE_CHANGED  时区改变
ACTION_BOOT_COMPLETED  系统启动完毕
ACTION_PACKAGE_ADDED  新的应用程序apk包安装完毕
ACTION_PACKAGE_CHANGED  现有应用程序apk包改变
ACTION_PACKAGE_REMOVED  现有应用程序apk包被删除
ACTION_UID_REMOVED  用户id被删除


Intent的Action和Data属性匹配
Action属性  Data属性  说明
ACTION_VIEW  content://contacts/people/1  显示id为1的联系人信息
ACTION_DIAL  content://contacts/people/1  将id为1的联系人电话号码显示在拨号界面中
ACITON_VIEW  tel:123  显示电话为123的联系人信息
ACTION_VIEW  http://www.google.com  在浏览器中浏览该网站
ACTION_VIEW  file://sdcard/mymusic.mp3  播放MP3
ACTION_VIEW  geo:39.2456,116.3523  显示地图


常见的Category常量
Category字符串常量  描述
CATEGORY_BROWSABLE  目标Activity能通过在网页浏览器中点击链接而激活(比如,点击浏览器中的图片链接)
CATEGORY_GADGET  表示目标Activity可以被内嵌到其他Activity当中
CATEGORY_HOME  目标Activity是HOME Activity,即手机开机启动后显示的Activity,或按下HOME键后显示的Activity
CATEGORY_LAUNCHER  表示目标Activity是应用程序中最优先被执行的Activity
CATEGORY_PREFERENCE  表示目标Activity是一个偏爱设置的Activity


常见的Extra常量
Extra键值字符串常量  描述
EXTRA_BCC  装有邮件密送地址的字符串数组
EXTRA_CC  装有邮件抄送地址的字符串数组
EXTRA_EMAIL  装有邮件发送地址的字符串数组
EXTRA_INTENT  使用ACTION_PICK_ACTIVITY动作时装有Intent选项的键
EXTRA_KEY_EVENT  触发该Intent的案件的KeyEvent对象
EXTRA_PHONE_NUMBER  使用拨打电话相关的Action时,电话号码字符串的键,类型为String
EXTRA_SHORTCUT_ICON  使用ACTION_CREATE_SHORTCUT在HomeActivity创建快捷方式时,对快捷方式的描述信息。
其中ICON和ICON_RESOURCE描述的是快捷方式的图标,类型分别为Bitmap和ShortcutIconResource。INTENT描述的是快捷方式相对应的Intent对象。NAME描述的是快捷方式的名字。
EXTRA_SHORTCUT_ICON_RESOURCE  EXTRA_SHORTCUT_INTENT  EXTRA_SHORTCUT_NAME  EXTRA_SUBJECT  描述信息主题的键
EXTRA_TEXT  使用ACTION_SEND动作时,用来描述要发送的文本信息,类型为CharSequence
EXTRA_TITLE  使用ACTION_CHOOSER动作时,描述对话框标题的键,类型为CharSequence
EXTRA_UID  使用ACTION_UID_REMOVED动作时,描述删除的用户id的键,类型为int


Android.telephony包中的类
类名  描述
CellLocation  表示设备位置的抽象类
PhoneNumberFormattingTextWather  监视一个TextView控件,如果有电话号码输入,则用formatNumber()方法处理电话号码
PhoneNumberUtils  包含各种处理电话号码字符串的使用工具
PhoneStateListener  监视手机中电话状态变化的监听类
ServiceState  包含电话状态和相关的服务信息
TelephonyManager  提供对手机中电话服务信息的访问


与短信服务相关的类主要在包android.telephony.gsm中
类名  描述
GsmCellLocation  表示GSM手机的基站位置
SmsManager  管理各种短信操作
SmsMessage  表示具体的短信


1.Intent的用法:
(1)用Action跳转
1、使用Action跳转,如果有一个程序的AndroidManifest.xml中的某一个 Activity的IntentFilter段中 定义了包含了相同的Action那么这个Intent就与这个目标Action匹配。如果这个IntentFilter段中没有定义 Type,Category,那么这个 Activity就匹配了。但是如果手机中有两个以上的程序匹配,那么就会弹出一个对话可框来提示说明。
Action 的值在Android中有很多预定义,如果你想直接转到你自己定义的Intent接收者,你可以在接收者的IntentFilter 中加入一个自定义的Action值(同时要设定 Category值为"android.intent.category.DEFAULT"),在你的Intent中设定该值为Intent的 Action,就直接能跳转到你自己的Intent接收者中。因为这个Action在系统中是唯一的。
2,data/type,你可以用Uri 来做为data,比如Uri uri = Uri.parse(http://www.google.com);
Intent i = new Intent(Intent.ACTION_VIEW,uri);手机的Intent分发过程中,会根据http://www.google.com 的scheme判断出数据类型type 。手机的Brower则能匹配它,在Brower的Manifest.xml中的IntenFilter中 首先有ACTION_VIEW Action,也能处理http:的type,
3, 至于分类Category,一般不要去在Intent中设置它,如果你写Intent的接收者,就在Manifest.xml的Activity的 IntentFilter中包含android.category.DEFAULT,这样所有不设置 Category(Intent.addCategory(String c);)的Intent都会与这个Category匹配。
4,extras(附 加信息),是其它所有附加信息的集合。使用extras可以为组件提供扩展信息,比如,如果要执行“发送电子邮件”这个动 作,可以将电子邮件的标题、正文等保存在extras里,传给电子邮件发送组件。
(2)用类名跳转
    Intent负责对应用中一次操作的动作、动作涉及数据、附加数据进行描 述,Android则根据此Intent的描述, 负责找到对应的组件,将 Intent传递给调用的组件,并完成组件的调用。Intent在这里起着实现调用者与被调用者之间的解耦作用。Intent传递过程中,要找 到目标消费者(另一个Activity,IntentReceiver或Service),也就是Intent的响 应者。
Intent intent = new Intent();
intent.setClass(context, targetActivy.class);
//或者直接用 Intent intent = new Intent(context, targetActivity.class);

startActivity(intent);
不过注意用类名跳转,需要在AndroidManifest.xml中申明activity

2.几种Intent的用法
android 中intent是经常要用到的。不管是页面牵转,还是传递数据,或是调用外部程序,系统功能都要用到intent。在做了一些intent的例子之后,整理了一下intent,希望对大家有用。由于intent内容太多,不可能真的写全,难免会有遗落,以后我会随时更新。如果你们有疑问或新的intent内容,希望交流。
★intent大全:
1.从google搜索内容
Intent intent = new Intent();
intent.setAction(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY,"searchString")
startActivity(intent);

2.浏览网页
Uri uri = Uri.parse("http://www.google.com");
Intent it  = new Intent(Intent.ACTION_VIEW,uri);
startActivity(it);

3.显示地图
Uri uri = Uri.parse("geo:38.899533,-77.036476");
Intent it = new Intent(Intent.Action_VIEW,uri);
startActivity(it);

4.路径规划
Uri uri = Uri.parse("http://maps.google.com/maps?f=dsaddr=startLat%20startLng&daddr=endLat%20endLng&hl=en");
Intent it = new Intent(Intent.ACTION_VIEW,URI);
startActivity(it);

5.拨打电话
Uri uri = Uri.parse("tel:xxxxxx");
Intent it = new Intent(Intent.ACTION_DIAL, uri);
startActivity(it);

6.调用发短信的程序
Intent it = new Intent(Intent.ACTION_VIEW);
it.putExtra("sms_body", "The SMS text");
it.setType("vnd.android-dir/mms-sms");
startActivity(it);

7.发送短信
Uri uri = Uri.parse("smsto:0800000123");
Intent it = new Intent(Intent.ACTION_SENDTO, uri);
it.putExtra("sms_body", "The SMS text");
startActivity(it);
String body="this is sms demo";
Intent mmsintent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("smsto", number, null));
mmsintent.putExtra(Messaging.KEY_ACTION_SENDTO_MESSAGE_BODY, body);
mmsintent.putExtra(Messaging.KEY_ACTION_SENDTO_COMPOSE_MODE, true);
mmsintent.putExtra(Messaging.KEY_ACTION_SENDTO_EXIT_ON_SENT, true);
startActivity(mmsintent);

8.发送彩信
Uri uri = Uri.parse("content://media/external/images/media/23");
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra("sms_body", "some text");
it.putExtra(Intent.EXTRA_STREAM, uri);
it.setType("image/png");
startActivity(it);
StringBuilder sb = new StringBuilder();
sb.append("file://");
sb.append(fd.getAbsoluteFile());
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mmsto", number, null));
// Below extra datas are all optional.
intent.putExtra(Messaging.KEY_ACTION_SENDTO_MESSAGE_SUBJECT, subject);
intent.putExtra(Messaging.KEY_ACTION_SENDTO_MESSAGE_BODY, body);
intent.putExtra(Messaging.KEY_ACTION_SENDTO_CONTENT_URI, sb.toString());
intent.putExtra(Messaging.KEY_ACTION_SENDTO_COMPOSE_MODE, composeMode);
intent.putExtra(Messaging.KEY_ACTION_SENDTO_EXIT_ON_SENT, exitOnSent);
startActivity(intent);

9.发送Email
Uri uri = Uri.parse("mailto:xxx@abc.com");
Intent it = new Intent(Intent.ACTION_SENDTO, uri);
startActivity(it);
Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra(Intent.EXTRA_EMAIL, "me@abc.com");
it.putExtra(Intent.EXTRA_TEXT, "The email body text");
it.setType("text/plain");
startActivity(Intent.createChooser(it, "Choose Email Client"));
Intent it=new Intent(Intent.ACTION_SEND);
String[] tos={"me@abc.com"};
String[] ccs={"you@abc.com"};
it.putExtra(Intent.EXTRA_EMAIL, tos);
it.putExtra(Intent.EXTRA_CC, ccs);
it.putExtra(Intent.EXTRA_TEXT, "The email body text");
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
it.setType("message/rfc822");
startActivity(Intent.createChooser(it, "Choose Email Client"));

Intent it = new Intent(Intent.ACTION_SEND);
it.putExtra(Intent.EXTRA_SUBJECT, "The email subject text");
it.putExtra(Intent.EXTRA_STREAM, "file:///sdcard/mysong.mp3");
sendIntent.setType("audio/mp3");
startActivity(Intent.createChooser(it, "Choose Email Client"));

10.播放多媒体
Intent it = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse("file:///sdcard/song.mp3");
it.setDataAndType(uri, "audio/mp3");
startActivity(it);
Uri uri = Uri.withAppendedPath(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, "1");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);

11.uninstall apk
Uri uri = Uri.fromParts("package", strPackageName, null);
Intent it = new Intent(Intent.ACTION_DELETE, uri);
startActivity(it);

12.install apk
Uri installUri = Uri.fromParts("package", "xxx", null);
returnIt = new Intent(Intent.ACTION_PACKAGE_ADDED, installUri);

13. 打开照相机
<1>Intent i = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
    this.sendBroadcast(i);
<2>long dateTaken = System.currentTimeMillis();
    String name = createName(dateTaken) + ".jpg";
    fileName = folder + name;
    ContentValues values = new ContentValues();
    values.put(Images.Media.TITLE, fileName);
    values.put("_data", fileName);
    values.put(Images.Media.PICASA_ID, fileName);
    values.put(Images.Media.DISPLAY_NAME, fileName);
    values.put(Images.Media.DESCRIPTION, fileName);
    values.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, fileName);
    Uri photoUri = getContentResolver().insert(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);

    Intent inttPhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    inttPhoto.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
    startActivityForResult(inttPhoto, 10);

14.从gallery选取图片
Intent i = new Intent();
i.setType("image/*");
i.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(i, 11);

15. 打开录音机
Intent mi = new Intent(Media.RECORD_SOUND_ACTION);
startActivity(mi);

16.显示应用详细列表
Uri uri = Uri.parse("market://details?id=app_id");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
//where app_id is the application ID, find the ID
//by clicking on your application on Market home
//page, and notice the ID from the address bar

刚才找app id未果,结果发现用package name也可以
Uri uri = Uri.parse("market://details?id=");
这个简单多了

17寻找应用
Uri uri = Uri.parse("market://search?q=pname:pkg_name");
Intent it = new Intent(Intent.ACTION_VIEW, uri);
startActivity(it);
//where pkg_name is the full package path for an application

18打开联系人列表
    <1>
    Intent i = new Intent();
    i.setAction(Intent.ACTION_GET_CONTENT);
    i.setType("vnd.android.cursor.item/phone");
    startActivityForResult(i, REQUEST_TEXT);

    <2>
    Uri uri = Uri.parse("content://contacts/people");
    Intent it = new Intent(Intent.ACTION_PICK, uri);
    startActivityForResult(it, REQUEST_TEXT);

19 打开另一程序
Intent i = new Intent();
ComponentName cn = new ComponentName("com.yellowbook.android2",
        "com.yellowbook.android2.AndroidSearch");
i.setComponent(cn);
i.setAction("android.intent.action.MAIN");
startActivityForResult(i, RESULT_OK);

20.调用系统编辑添加联系人(高版本SDK有效):
Intent it = newIntent(Intent.ACTION_INSERT_OR_EDIT);
it.setType("vnd.android.cursor.item/contact");
//it.setType(Contacts.CONTENT_ITEM_TYPE);
it.putExtra("name","myName");
it.putExtra(android.provider.Contacts.Intents.Insert.COMPANY,  "organization");
it.putExtra(android.provider.Contacts.Intents.Insert.EMAIL,"email");
it.putExtra(android.provider.Contacts.Intents.Insert.PHONE,"homePhone");
it.putExtra(android.provider.Contacts.Intents.Insert.SECONDARY_PHONE,
               "mobilePhone");
it.putExtra(  android.provider.Contacts.Intents.Insert.TERTIARY_PHONE,
               "workPhone");
it.putExtra(android.provider.Contacts.Intents.Insert.JOB_TITLE,"title");
startActivity(it);

21.调用系统编辑添加联系人(全有效):
Intent intent = newIntent(Intent.ACTION_INSERT_OR_EDIT);
intent.setType(People.CONTENT_ITEM_TYPE);
intent.putExtra(Contacts.Intents.Insert.NAME, "My Name");
intent.putExtra(Contacts.Intents.Insert.PHONE, "+1234567890");
intent.putExtra(Contacts.Intents.Insert.PHONE_TYPE,Contacts.PhonesColumns.TYPE_MOBILE);
intent.putExtra(Contacts.Intents.Insert.EMAIL, "com@com.com");
intent.putExtra(Contacts.Intents.Insert.EMAIL_TYPE,                    Contacts.ContactMethodsColumns.TYPE_WORK);
startActivity(intent);

UI控件

View

处理文本内容的View(TextView) 

被点击的View(Button)

处理图片内容的View(ImageView)

接收用户信息输入的View(EditText)

进度条类的View(ProgressBar)

通用属性

 

TextView

TextView的继承关系

 

长文本处理 

新建Activity

文本资源

res目录的values目录下

strings.xml

<resources>
    <string name="app_name">My Applicationstring>
    <string name="long_txt">
        10月22日,在国新办新闻发布会上,针对受到广泛的关注的App违规收集使用个人信息的问题,工业和信息化部新闻发言人、信息通信发展司司长闻库表示,当前工信部里已经完成了国内主流应用商店32万款APP的技术检测工作,督促1100多家企业进行整改。
        闻库表示,工业和信息化部作为电信行业的主管部门,非常重视电信和互联网领域个人用户信息保护工作,严格贯彻落实《网络安全法》,颁布实施了《电信和互联网用户个人信息保护规定》和智能终端、应用程序等重点领域个人信息保护制度;并依法履职主动作为,按照“发现、取证、处置、曝光”工作机制,强化监督检查,聚焦大家所反映热烈的、社会也高度关注的APP侵害用户权益的行为。已经连续两年组织开展了相关的整治行动,持续加大个人信息的保护力度。
        闻库表示,去年,工信部重点整治了“私自收集个人信息”“超范围收集个人信息”“不给权就不让使用App”“过度索取权限”等8类损害用户权益的行为。
        闻库表示,今年,工信部在去年工作的基础上,还加强对App常使用的SDK以及应用分发平台的监管,重点针对“APP、SDK违规处理个人用户信息”“设置障碍、频繁骚扰用户”“欺骗误导用户”“应用分发平台责任落实不到位”等四个方面10类问题进行集中专项整治。
        闻库表示,目前,工信部里已经完成了国内主流应用商店32万款App的技术检测工作,督促1100多家企业进行整改,公开通报了246款未在期限内完成整改的App。根据整改的情况,下架了34款拒不整改的App。这项工作取得了很大成效,社会上对这项工作寄予了很大的期望。
        闻库表示,下一步,工信部将继续坚持以人民为中心,以老百姓和社会反映的问题为导向,积极从完善制度规范、加强常态化监管、提升技术检测能力、推动行业自律等多个方面,进一步加大工作力度,切实在个人信息保护方面实现好、维护好广大人民群众的合法利益。
    string>
resources>

布局文件里引用

<?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:layout_height="match_parent"
    tools:context="com.example.TextActivity">
    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/long_txt"
        android:textSize="5sp"
        android:textColor="#00ffff"
        android:lineSpacingMultiplier="2"/>
LinearLayout>

如果文字太多,一屏显示不过来怎么办?

使用滚动条。

<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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:layout_height="match_parent"
    tools:context="com.example.TextActivity">
    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/long_txt"
        android:textSize="5sp"
        android:textColor="#00ffff"
        android:lineSpacingMultiplier="2"/>
ScrollView>

ScrollView 中只能有一个直接子空间,因此不能放两个 TextView,如果想放请在外部先放一个布局

可以只显示一行

       <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/long_txt"
        android:singleLine="true" />

可以控制上面的省略号

    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/long_txt"
        android:singleLine="true"
        android:ellipsize="start"/>

 可以设置跑马灯

    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="@string/long_txt"
        android:singleLine="true"
        android:ellipsize="marquee"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:marqueeRepeatLimit="marquee_forever"/>

TextView的文字动态赋值,高版本直接写在布局Xml里面已经不生效了,需要先给TextView赋值,然后再在代码里面重新把属性设置一遍:

    public static void setTextMarquee(TextView textView) {
        if (textView != null) {
            textView.setEllipsize(TextUtils.TruncateAt.MARQUEE);
            textView.setSingleLine(true);
            textView.setSelected(true);
            textView.setFocusable(true);
            textView.setFocusableInTouchMode(true);
        }
    }

EditText

输入框

    
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="200dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:inputType="textEmailAddress"/>

设置提示

设置最大长度

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="40dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:inputType="textEmailAddress"
        android:hint="Email"
        android:gravity="center"
        android:textColorHint="#cccccc"
        android:maxLength="12"/>

gravity是设置自身内部元素的对齐方式。比如一个TextView,则是设置内部文字的对齐方式。如果是ViewGroup组件如LinearLayout的话,则为设置它内部view组件的对齐方式。

 layout_gravity是设置自身相当于父容器的对齐方式。比如,一个TextView设置layout_gravity属性,则表示这TextView相对于父容器的对齐方式。

事件监听

四种实现

<?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:layout_height="match_parent"
    tools:context="com.example.ButtonActivity"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="通过自定义内部类实现点击事件"/>
    <Button
        android:id="@+id/btn2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="通过自匿名内部类实现点击事件"/>
    <Button
        android:id="@+id/btn3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="通过当前Activity实现点击事件"/>
    <Button
        android:id="@+id/btn4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="XML中绑定"/>
LinearLayout>

自定义内部类

public class ButtonActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_button);
        // 1.获取按钮
        Button btn1 = findViewById(R.id.btn1);
        // 点击事件:被点击时触发的事件
        MyClickListener mc1 = new MyClickListener();
        // 2.为按钮注册点击事件监听器,参数是接口,下面用自定义内部类 MyClickListener 来实现该接口
        btn1.setOnClickListener(mc1);
    }
    // 自定义内部类
    class MyClickListener implements View.OnClickListener{
        // 点击按钮后执行的操作 onClick,即点击后的回调方法
        @Override
        public void onClick(View v) {
            // 弹出对话框
            new AlertDialog.Builder(ButtonActivity.this)
                    .setTitle("hello")
                    .setMessage("This is a button message!")
                    .setPositiveButton("确定", null)
                    .show();
        }
    }
}

匿名内部类

public class ButtonActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_button);
        // 1.获取按钮
        Button btn2 = findViewById(R.id.btn2);

        // 2.为按钮注册点击事件监听器,使用匿名内部类
        btn2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new AlertDialog.Builder(ButtonActivity.this)
                        .setTitle("hello")
                        .setMessage("This is a button message!")
                        .setPositiveButton("确定", null)
                        .show();
            }
        });
    }
}

适合有唯一操作的按钮

通过当前Activity实现点击事件

可以自己实现接口,然后注册自己就可以了

public class ButtonActivity extends AppCompatActivity implements View.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_button);
        // 1.获取按钮
        Button btn3 = findViewById(R.id.btn3);

        // 2.为按钮注册点击事件监听器
        btn3.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        new AlertDialog.Builder(ButtonActivity.this)
                .setTitle("hello")
                .setMessage("This is a button message!")
                .setPositiveButton("确定", null)
                .show();
    }
}

在XML中绑定

    <Button
        android:id="@+id/btn4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="XML中绑定"
        android:onClick="myClick"/>

频繁使用

public class ButtonActivity extends AppCompatActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_button);
    }
    
    // 在XML中注册
    public void myClick(View v) {
        new AlertDialog.Builder(ButtonActivity.this)
                .setTitle("hello")
                .setMessage("This is a button message!")
                .setPositiveButton("确定", null)
                .show();
    }
}

你会发现代码中只定义了方法并没有调用

参数 View 类型,Button继承了该类,不仅Button有点击事件,其他View类也有。

多个按钮

    <Button
        android:id="@+id/btn4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="btn4:XML中绑定"
        android:onClick="myClick"/>
    <Button
        android:id="@+id/btn5"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="btn5:XML中绑定"
        android:onClick="myClick"/>
public class ButtonActivity extends AppCompatActivity{

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

    // 在XML中注册
    public void myClick(View v) {
        switch (v.getId()){
            case R.id.btn4:
                new AlertDialog.Builder(ButtonActivity.this)
                        .setTitle("hello")
                        .setMessage("This is a btn4 message!")
                        .setPositiveButton("确定", null)
                        .show();
                break;
            case R.id.btn5:
                new AlertDialog.Builder(ButtonActivity.this)
                        .setTitle("hello")
                        .setMessage("This is a btn5 message!")
                        .setPositiveButton("确定", null)
                        .show();
                break;
        }
    }
}

ImageView

显示和控制图像的空间,可以放大、缩小、旋转

常用属性

android:src
android:background

将图片放在资源文件夹中

图片命名:小写英文字母、数字(不能开头)、下划线

文件夹

mipmap 图片暂时都放该文件夹

drawable 

    
    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher_round"
        android:background="@mipmap/ic_launcher"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="50dp"/>
    
    <ImageButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"
        android:layout_marginTop="5dp"
        android:layout_marginLeft="50dp"/>

ProgressBar

 进度条,默认是圆形,没有刻度,只是一个不断旋转的动画效果。通过设置style,可以显示传统的水平刻度进度条。

<?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:layout_height="match_parent"
    tools:context="com.example.ProgressBar">

    
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
LinearLayout>

可以修改风格

<?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:layout_height="match_parent"
    tools:context="com.example.ProgressBar"
    android:orientation="vertical">

    
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="?android:attr/progressBarStyleHorizontal"
        android:progress="30"
        android:max="200"/>

    
    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="?android:attr/progressBarStyleHorizontal"
        android:indeterminate="true"/>
LinearLayout>

使用代码操作进度条的进度

    <ProgressBar
        android:id="@+id/pb1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="?android:attr/progressBarStyleHorizontal"/>

新建一个线程,专门操作进度条,每30毫秒进度条加1

public class ProgressBarActivity extends AppCompatActivity {

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

        final ProgressBar pb = findViewById(R.id.pb1);
        pb.setProgress(80);
        new Thread(){
            @Override
            public void run() {
                for (int i=1; i<100; i++){
                    pb.setProgress(i);
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }
}

注意:Android4以后是不能直接在线程中操作控件的,否则程序崩溃。进度条是个特例。

Menu

3.0是个分水岭

3.0当用户按”菜单“按钮时,选项菜单的内容会出现在屏幕底部,可包含多达6个菜单项,超出部分则以”更多“来显示。

3.0以后,选项菜单中的项目将出现在操作栏中,用户可以使用操作栏右侧的图标或者按设备的菜单键显示操作溢出菜单。

 分类

  • 选项菜单  option menu
  • 上下文菜单  context menu
  • 弹出菜单  popup menu

选项菜单

 选项菜单是一个应用的主菜单项,用于放置对应用产生全局影响的操作

创建

新建资源目录

 

 然后,新建menu resource file

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:title="保存"/>
    <item android:title="设置"/>
    <item android:title="更多操作">
        
        <menu>
            <item android:title="子菜单1"/>
            <item android:title="子菜单2"/>
            <item android:title="子菜单3"/>
        menu>
    item>
menu>

 显示到页面中,代码操作

public class MainActivity extends AppCompatActivity {

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

    // 覆盖下面方法
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // 加载菜单资源
        getMenuInflater().inflate(R.menu.option, menu);
        return true;
    }
}

属性

显示图标,always总是显示,直接在标题栏显示

    <item android:title="保存"
        android:icon="@mipmap/ic_launcher"
        app:showAsAction="always"
        />

同时显示图标和文本

    <item android:title="保存"
        android:icon="@mipmap/ic_launcher"
        app:showAsAction="always|withText"
        />

ifRoom 有空间就显示

选中menu时操作

添加id

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item android:title="保存"
        android:id="@+id/save"
        android:icon="@mipmap/ic_launcher"
        app:showAsAction="always|withText"
        />
    <item android:title="设置" android:id="@+id/setting"/>
    <item android:title="更多操作">
        
        <menu>
            <item android:title="退出" android:id="@+id/exit"/>
            <item android:title="子菜单2"/>
            <item android:title="子菜单3"/>
        menu>
    item>
menu>
public class MainActivity extends AppCompatActivity {

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

    // 覆盖下面方法
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // 加载菜单资源
        getMenuInflater().inflate(R.menu.option, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case R.id.save:
                Toast.makeText(this, "保存", Toast.LENGTH_SHORT).show();
                break;
            case R.id.exit:
                finish();
                break;
        }
        return super.onOptionsItemSelected(item);
    }
}

上下文Menu

长按某个view不放,就会在屏幕出现上下文菜单

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 1.注册
        registerForContextMenu(findViewById(R.id.button1));
        // 2.创建,覆盖 onCreateContextMenu
        // 3.菜单项的操作,覆盖 onContextItemSelected

    }// 上下菜单的创建
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        getMenuInflater().inflate(R.menu.context, menu);
    }

    @Override
    public boolean onContextItemSelected(@NonNull MenuItem item) {
        switch (item.getItemId()){
            case R.id.delete:
                Toast.makeText(this, "已删除", Toast.LENGTH_SHORT).show();
                break;
            case R.id.rename:
                Toast.makeText(this, "请输入名字", Toast.LENGTH_SHORT).show();
                break;
        }
        return super.onContextItemSelected(item);
    }

}

上下文操作模式

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
// 4.1 实现接口 ActionMode CallBack
        // 4.2 在view的长按事件中启动上下文操作模式
        findViewById(R.id.button1).setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                startActionMode(cb);
                return false;
            }
        });
    }

    ActionMode.Callback cb = new ActionMode.Callback() {
        // 创建,在启动上下文操作模式(startActionMode(Callback))时调用
        // 返回 true
        @Override
        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            getMenuInflater().inflate(R.menu.context, menu);
            return true;
        }
        // 在创建方法后调用
        @Override
        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return false;
        }

        // 菜单项被点击
        @Override
        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            switch (item.getItemId()){
                case R.id.delete:
                    Toast.makeText(MainActivity.this, "已删除", Toast.LENGTH_SHORT).show();
                    break;
                case R.id.rename:
                    Toast.makeText(MainActivity.this, "请输入名字", Toast.LENGTH_SHORT).show();
                    break;
            }
            return true;
        }
        // 上下文操作模式结束时被调用
        @Override
        public void onDestroyActionMode(ActionMode mode) {
            Toast.makeText(MainActivity.this, "已结束", Toast.LENGTH_SHORT).show();
        }
    };

弹出菜单

 一个模态形式展示的弹出风格菜单,绑在某个View上,一般出现在被绑定的View下方

绑定在点击事件上

布局文件中的按钮

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="弹出菜单"/>

菜单资源文件

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:title="保存" android:id="@+id/save"/>
    <item android:title="删除" android:id="@+id/delete"/>
menu>

代码

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final Button popupBtn = findViewById(R.id.button2);
// 按钮的监听 popupBtn.setOnClickListener(
new View.OnClickListener() { @Override public void onClick(View v) { // 1) 实例化PopupMenu对象,参数二是被锚定的view PopupMenu popupMenu = new PopupMenu(MainActivity.this, popupBtn); // 2) 加载菜单资源:利用Menuflater将menu资源加载到PopupMenu.getMenu()所返回的Menu对象中 // 将R.menu.xx对于菜单的资源加载到弹出式菜单中,即第一个参数加载到第二个参数 popupMenu.getMenuInflater().inflate(R.menu.popup, popupMenu.getMenu());
// 菜单的监听
// 3) 为PopupMenu设置点击监听器 popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { switch (item.getItemId()){ case R.id.delete: Toast.makeText(MainActivity.this, "已删除", Toast.LENGTH_SHORT).show(); break; case R.id.save: Toast.makeText(MainActivity.this, "已保存", Toast.LENGTH_SHORT).show(); break; } return false; } }); // 4) show,千万不能忘 popupMenu.show(); } }); } }

对话框

消息提示机制,常用于向用户传递信息、提示或警告用户的行动。通用方法:

  • setTitle
  • setMessage
  • create
  • show
<?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:layout_height="match_parent"
    tools:context="com.example.MainActivity">

    <Button
        android:id="@+id/normal_dialog_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="显示一个普通的对话框"
        android:onClick="myClick" />

    <Button
        android:id="@+id/diy_dialog_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="显示一个自定义对话框"
        android:onClick="myClick"/>

LinearLayout>
public class MainActivity extends AppCompatActivity {

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

    public void myClick(View view){
        switch (view.getId()){
            case R.id.normal_dialog_btn:
// 1.实例化一个Builder
// AlertDialog 的构造方法是protected的 AlertDialog.Builder builder = new AlertDialog.Builder(this);
// 2.设置对话框样式 builder.setTitle(
"提示"); builder.setMessage("您确定退出程序吗?");
// 设置按钮 builder.setPositiveButton(
"确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }); // 取消,什么都不做 builder.setNegativeButton("取消", null);
// 3.显示 builder.show();
// 等价于 // AlertDialog dialog = builder.create(); // dialog.show(); break; case R.id.diy_dialog_btn: break; } } }

自定义对话框

  • 设置布局
  • 设置style
  • 自定义Dialog
  • 显示

素材

创建布局

dialog_layout.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:layout_height="match_parent"
    tools:context="com.example.MainActivity"
    android:orientation="vertical"
    android:gravity="center_horizontal"
    android:background="@mipmap/dialog_bg">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="宝宝,确定要退出吗?"
        android:textSize="34sp"
        android:textColor="#e61414"
        android:textStyle="bold"
        android:layout_marginTop="450dp"/>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_margin="50dp">
        <Button
            android:id="@+id/yes_btn"
            android:layout_width="120dp"
            android:layout_height="50dp"
            android:background="@mipmap/yes_btn"/>
        <Button
            android:id="@+id/no_btn"
            android:layout_width="120dp"
            android:layout_height="50dp"
            android:background="@mipmap/no_btn"
            android:layout_marginLeft="20dp"/>
    LinearLayout>
LinearLayout>

style设置

去掉标题栏,去掉背景

<resources>

    
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        
        <item name="colorPrimary">@color/colorPrimaryitem>
        <item name="colorPrimaryDark">@color/colorPrimaryDarkitem>
        <item name="colorAccent">@color/colorAccentitem>
    style>
    
    <style name="mydialog" parent="android:style/Theme.Dialog">
        
        <item name="android:windowNoTitle">trueitem>
        
        <item name="android:windowBackground">@android:color/transparentitem>
    style>
resources>

自定义类

参数一是环境上下文,参数二是上面的style

public class MyDialog extends Dialog {

    public MyDialog(@NonNull Context context, int themeResId) {
        super(context, themeResId);
        // 为对话框设置布局
        setContentView(R.layout.dialog_layout);
        findViewById(R.id.yes_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 对话框没有finish方法
                System.exit(0);
            }
        });
        findViewById(R.id.no_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 对话框消失
                dismiss();
            }
        });
    }
}

使用

public class MainActivity extends AppCompatActivity {

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

    public void myClick(View view){
        switch (view.getId()){
            case R.id.normal_dialog_btn:
                // AlertDialog 的构造方法是protected的
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setTitle("提示");
                builder.setMessage("您确定退出程序吗?");
                builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                });
                // 取消,什么都不做
                builder.setNegativeButton("取消", null);
                builder.show();
                // 等价于
//                AlertDialog dialog = builder.create();
//                dialog.show();
                break;
            case R.id.diy_dialog_btn:
                MyDialog md = new MyDialog(this, R.style.mydialog);
                md.show();
                break;
        }
    }
}

PopupWindow

 使用步骤:

  • 1.创建PopupWindow对象实例
  • 2.设置背景、注册事件监听器和添加动画
  • 3.显式PopupWindow

控制出现的位置和出现的方式

布局文件 activity_main.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:layout_height="match_parent"
    tools:context="com.example.MainActivity"
    android:orientation="vertical">

    <Button
        android:id="@+id/normal_dialog_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="显示一个普通的对话框"
        android:onClick="myClick" />

    <Button
        android:id="@+id/diy_dialog_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="显示一个自定义对话框"
        android:onClick="myClick"/>

    <Button
        android:id="@+id/popup_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="显式弹窗"
        android:layout_gravity="center_horizontal"
        android:onClick="myClick"/>

LinearLayout>

弹窗布局文件popup_layout.xml

<?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="wrap_content"
    android:orientation="horizontal"
    android:background="#00ffff"
    android:padding="2dp">

    <TextView
        android:id="@+id/choose"
        android:layout_width="60dp"
        android:layout_height="30dp"
        android:text="选择"
        android:textColor="#ffffff"
        android:gravity="center"
        android:background="#000000"/>
    <TextView
        android:id="@+id/selectall"
        android:layout_width="60dp"
        android:layout_height="30dp"
        android:text="全选"
        android:textColor="#ffffff"
        android:gravity="center"
        android:background="#000000"/>
    <TextView
        android:id="@+id/copy"
        android:layout_width="60dp"
        android:layout_height="30dp"
        android:text="复制"
        android:textColor="#ffffff"
        android:gravity="center"
        android:background="#000000"/>
LinearLayout>

代码

public class MainActivity extends AppCompatActivity {

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

    public void myClick(View view){
        switch (view.getId()){
            case R.id.normal_dialog_btn:
                // AlertDialog 的构造方法是protected的
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setTitle("提示");
                builder.setMessage("您确定退出程序吗?");
                builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                });
                // 取消,什么都不做
                builder.setNegativeButton("取消", null);
                builder.show();
                // 等价于
//                AlertDialog dialog = builder.create();
//                dialog.show();
                break;
            case R.id.diy_dialog_btn:
                MyDialog md = new MyDialog(this, R.style.mydialog);
                md.show();
                break;
            case R.id.popup_btn:
                showPopupWindow(view);
                break;
        }
    }

    // 设置popupWindow
    public void showPopupWindow(View view){
        // 准备弹出所需要的视图对象
        View v = LayoutInflater.from(this).inflate(R.layout.popup_layout, null);
        // 1.实例化对象

        // 参数1:用在弹窗中的view
        // 参数2、3:弹窗的宽高
        // 参数4(focusable):能否获取焦点
        final PopupWindow window = new PopupWindow(v, 520, 100, true);
        // 2.设置(背景,图画) 不设置,点屏幕弹窗框不消失
        // 设置背景
        window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        // 设置能响应外部的点击事件
        window.setOutsideTouchable(true);
        // 设置能响应点击事件
        window.setTouchable(true);
        // 3.显示
        // 参数1:anchor,锚,这里以按钮为参照物
        // 参数2、3:相对于锚在x、y方向的偏移量
        window.showAsDropDown(view, 20, 20);
        // 为弹窗中的文本添加点击事件
        // 如果直接findViewById()是在activity_main中找
        v.findViewById(R.id.choose).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "您点击了选择", Toast.LENGTH_SHORT ).show();
                // 弹窗消失
                window.dismiss();
            }
        });
        v.findViewById(R.id.selectall).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "您点击了全选", Toast.LENGTH_SHORT ).show();
                window.dismiss();
            }
        });
        v.findViewById(R.id.copy).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "您点击了复制", Toast.LENGTH_SHORT ).show();
                window.dismiss();
            }
        });

可以添加动画

创建动画资源文件

新建动画资源目录 anim,文件translate_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:toXDelta="0"
        android:fromYDelta="300"
        android:toYDelta="0"
        android:duration="2000"
        >translate>
set>

styles.xml中添加

    <style name="translate_anim">
        <item name="android:windowEnterAnimation">@anim/translate_animitem>
    style>

代码

 // 设置popupWindow
    public void showPopupWindow(View view){
        // 准备弹出所需要的视图对象
        View v = LayoutInflater.from(this).inflate(R.layout.popup_layout, null);
        // 1.实例化对象

        // 参数1:用在弹窗中的view
        // 参数2、3:弹窗的宽高
        // 参数4(focusable):能否获取焦点
        final PopupWindow window = new PopupWindow(v, 520, 100, true);
        // 2.设置(背景,图画)
        // 设置背景
        window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        // 设置能响应外部的点击事件
        window.setOutsideTouchable(true);
        // 设置能响应点击事件
        window.setTouchable(true);
        // 1.创建动画资源 2.创建一个style应用动画资源 3.对当前弹窗的动画设置为第二步的资源索引
        window.setAnimationStyle(R.style.translate_anim);
        // 3.显示
        // 参数1:anchor,锚,这里以按钮为参照物
        // 参数2、3:相对于锚在x、y方向的偏移量
        window.showAsDropDown(view, 20, 20);
        // 为弹窗中的文本添加点击事件
        // 如果直接findViewById()是在activity_main中找
        v.findViewById(R.id.choose).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "您点击了选择", Toast.LENGTH_SHORT ).show();
                // 弹窗消失
                window.dismiss();
            }
        });
        v.findViewById(R.id.selectall).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "您点击了全选", Toast.LENGTH_SHORT ).show();
                window.dismiss();
            }
        });
        v.findViewById(R.id.copy).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "您点击了复制", Toast.LENGTH_SHORT ).show();
                window.dismiss();
            }
        });
    }

ArrayAdapter

数组适配器,只能用来显示单一的文本。构造方法:

ArrayAdapter(Context context, int resource, int textviewId, List objects)
    <Button
        android:id="@+id/btn6"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="数组适配器"
        android:onClick="myClick"/>
public class MainActivity extends AppCompatActivity {

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

    public void myClick(View view){
        switch (view.getId()){
            case R.id.normal_dialog_btn:
                // AlertDialog 的构造方法是protected的
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setTitle("提示");
                builder.setMessage("您确定退出程序吗?");
                builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                });
                // 取消,什么都不做
                builder.setNegativeButton("取消", null);
                builder.show();
                // 等价于
//                AlertDialog dialog = builder.create();
//                dialog.show();
                break;
            case R.id.diy_dialog_btn:
                MyDialog md = new MyDialog(this, R.style.mydialog);
                md.show();
                break;
            case R.id.popup_btn:
                showPopupWindow(view);
                break;
            case R.id.btn6:
                showArrayDialog();
                break;
        }
    }

    private void showArrayDialog(){
        final String[] items = {"Java", "Mysql", "C"};
        // 数组适配器
        // 参数1:环境
        // 参数2:布局资源索引,指的是每一项数据所呈现的样式 android.R.layout.xxx
        // 参数3:数据源
        ArrayAdapter adpter = new ArrayAdapter(this,android.R.layout.simple_dropdown_item_1line, items);
        
        AlertDialog.Builder builder = new AlertDialog.Builder(this)
                .setTitle("请选择")
                .setAdapter(adpter, null); // 参数1:适配器对象(对数据显示样式的规则指定器) 参数2:监听器
        builder.show();
    }

  
}

但是上面只能显示文字,不能显示图片

自定义布局

<?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="wrap_content"
    android:orientation="horizontal"
    android:padding="10dp"
    android:gravity="center_vertical">
    
    <ImageView
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:src="@mipmap/star"/>

    <TextView
        android:id="@+id/item_txt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="测试"/>

LinearLayout>

修改代码

  ArrayAdapter adpter = new ArrayAdapter(this,android.R.layout.simple_dropdown_item_1line, items);

 android.R.layout.simple_dropdown_item_1line ,你会发现其根元素是TextView
而我们这里为了显示图片,肯定不能是TextView,那就指出TextView,否则会出错,下面的id就是TextView的id

参数二为自定义布局,参数三修改为textView的id了:

        // 参数3:数据源
        //ArrayAdapter adpter = new ArrayAdapter(this,android.R.layout.simple_dropdown_item_1line, items);
        // 参数3:int textviewId,指定文本需要放在布局中对应id文本控制的位置
        ArrayAdapter adpter = new ArrayAdapter(this, R.layout.arrayadapter_layout,R.id.item_txt, items);

这就可以显示前面星星,后面文字

当然,可以添加点击监听器

        AlertDialog.Builder builder = new AlertDialog.Builder(this)
                .setTitle("请选择")
                .setAdapter(adpter, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int i) {
                        Toast.makeText(MainActivity.this, items[i], Toast.LENGTH_SHORT).show();
                        dialog.dismiss();
                    }
                }); // 参数1:适配器对象(对数据显示样式的规则指定器) 参数2:监听器

Fragment

为什么使用Fragment?

Fragment的出现可以一次编写,适应不同的屏幕,不用每个类型的屏幕编写一套代码。 

检测到是平板的时候,FragmentA、FragmentB组成一个ActivityA,显示在整个平板平面上。

当检测是手机的时候,可以用两个Activity,一个包含FramnetA,另一个包含FragmentB,分别显示。

生命周期

 

静态加载和动态加载

静态使用XML,动态使用代码

 静态加载

实现当点击的时候,会出现两个Fragment

点击 static load fragment

出现两个红块

 第一个Activity布局

<?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:layout_height="match_parent"
    tools:context="com.example.MainActivity"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:gravity="center"
        android:text="static load fragment" />

LinearLayout>

点击textView,跳转到第二个Activity,第二个Activity由Fragment组成

下面在第一个Activity中设置了跳转第二个Activity的点击事件

public class MainActivity extends AppCompatActivity {

    public static final String BUTTON_TITLE = "button_title";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // setContentView(R.layout.activity_main);
        setContentView(R.layout.activity_main);
        findViewById(R.id.textView).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this, StaticLoadFragment.class));
            }
        });
    }

}

点击后会跳转第二个Activity

public class StaticLoadFragment extends AppCompatActivity {

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

加载XML文件来显示Fragment

activity_static_load_fragment.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:layout_height="match_parent"
    android:orientation="vertical">

   <fragment
       android:id="@+id/listFragment"
       android:name="com.example.ListFragment"
       android:layout_width="100dp"
       android:layout_height="100dp"/>
LinearLayout>

通过  android:name="com.example.ListFragment"  来静态绑定一个类,这个类可以配置在Fragment中显示什么

可以有两个Fragment

<?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:layout_height="match_parent"
    android:orientation="vertical">

   <fragment
       android:id="@+id/listFragment"
       android:name="com.example.ListFragment"
       android:layout_width="100dp"
       android:layout_height="100dp"/>
   <fragment
       android:id="@+id/DetailFragment"
       android:name="com.example.ListFragment"
       android:layout_marginTop="200dp"
       android:layout_gravity="center_horizontal"
       android:layout_width="100dp"
       android:layout_height="100dp"/>
LinearLayout>

 注意:  android:name="com.example.ListFragment" ,即指向一个Fragment实现类,是每个布局必须有的,否则是个空的fragment,会报空指针异常。

id不同,指向的Fragment类相同

下面创建 ListFragment 类

实现 Fragment

主要的生命周期是 onCreateView

里面可以创建你想要在Fragment中显示的东西

public class ListFragment  extends Fragment {

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    // 创建视图
    // 主要使用的
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_layout, container, false);
        TextView v = view.findViewById(R.id.textview);
        v.setText("aidata");
        return view;
    }

    @Override
    public void onStart() {
        super.onStart();
    }

    @Override
    public void onPause() {
        super.onPause();
    }

    @Override
    public void onStop() {
        super.onStop();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

 View view = inflater.inflate(R.layout.fragment_layout, container, false) ,Fragment也可以加载布局文件来装饰自己

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorAccent">

    <TextView
        android:id="@+id/textview"
        android:layout_width="match-parent"
        android:layout_height="match-parent"
        android:background="#ff0000"
        android:textColor="#ffffff"
        android:textSize="20sp"
        android:text="TextView"/>
RelativeLayout>

里面有TextView

动态加载

第二个Activity不再加载Fragment的布局文件

需要容器

在布局文件中定义两个布局作为容器来放Fragment

<?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:layout_height="match_parent"
    tools:context="com.example.MainActivity"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:gravity="center"
        android:text="static load fragment" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">
        <LinearLayout
            android:id="@+id/listContainer"
            android:orientation="horizontal"
            android:layout_margin="2dp"
            android:layout_width="150dp"
            android:layout_height="match_parent"
            >
        LinearLayout>
        <LinearLayout
            android:id="@+id/detailContainer"
            android:orientation="horizontal"
            android:layout_margin="2dp"
            android:layout_width="250dp"
            android:layout_height="match_parent">
        LinearLayout>
    LinearLayout>
LinearLayout>

代码

public class MainActivity extends AppCompatActivity {

    public static final String BUTTON_TITLE = "button_title";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // setContentView(R.layout.activity_main);
        setContentView(R.layout.activity_main);
        findViewById(R.id.textView).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this, StaticLoadFragment.class));
            }
        });
        // 1.container 2.fragment 3.fragment-->container
        ListFragment fragment = new ListFragment();
        getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.listContainer, fragment)
                .commit();
        // 一个fragment用一次,这里新建一个
        getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.detailContainer, new ListFragment())
                .commit();
        // 移除
        getSupportFragmentManager()
                .beginTransaction()
                .remove(fragment)
                .commit();
    }
}

Activity向Fragment传值

setAarguments()

public class ListFragment  extends Fragment {

    public static final String BUNDLE_TITLE = "bundle_title";
    private String title = "aidata";

    // activity传进来的值
    public static ListFragment newInstance(String title){
        ListFragment fragment = new ListFragment();
        Bundle bundle = new Bundle();
        bundle.putString(BUNDLE_TITLE, title);
        fragment.setArguments(bundle);
        return fragment;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 接收 arguments 传进来的值
        if (getArguments() != null){
            title = getArguments().getString(BUNDLE_TITLE);
        }
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    // 创建视图
    // 主要使用的
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_layout, container, false);
        TextView v = view.findViewById(R.id.textview);
        // 使用传进来的值
        v.setText(title);
        return view;
    }

    @Override
    public void onStart() {
        super.onStart();
    }

    @Override
    public void onPause() {
        super.onPause();
    }

    @Override
    public void onStop() {
        super.onStop();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}
public class MainActivity extends AppCompatActivity {

    public static final String BUTTON_TITLE = "button_title";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // setContentView(R.layout.activity_main);
        setContentView(R.layout.activity_main);
        findViewById(R.id.textView).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this, StaticLoadFragment.class));
            }
        });
        // 1.container 2.fragment 3.fragment-->container
        // 传值的时候不再需要无参构造函数
        //ListFragment fragment = new ListFragment();
        getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.listContainer, ListFragment.newInstance("list"))
                .commit();
        // 一个fragment用一次,这里新建一个
        getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.detailContainer, ListFragment.newInstance("detail"))
                .commit();
        // 移除
//        getSupportFragmentManager()
//                .beginTransaction()
//                .remove(fragment)
//                .commit();
    }
}

你会发现add的时候添加了Fragment对象,对象中有了参数,但是Fragment对象中onCreate()等方法还没被执行。

Fragment向Activity传值

使用回调的方式

定义接口接口

public class ListFragment  extends Fragment {

    public static final String BUNDLE_TITLE = "bundle_title";
    private String title = "aidata";

    // activity传进来的值
    public static ListFragment newInstance(String title){
        ListFragment fragment = new ListFragment();
        Bundle bundle = new Bundle();
        bundle.putString(BUNDLE_TITLE, title);
        fragment.setArguments(bundle);
        return fragment;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 接收 arguments 传进来的值
        if (getArguments() != null){
            title = getArguments().getString(BUNDLE_TITLE);
        }
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }

    // 创建视图
    // 主要使用的
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_layout, container, false);
        TextView v = view.findViewById(R.id.textview);
        // 使用传进来的值
        v.setText(title);

        v.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 当外界调用了其set方法时不为空
                if (onTitleClickListener != null){
                    onTitleClickListener.onClick(title);
                }
            }
        });

        return view;
    }

    @Override
    public void onStart() {
        super.onStart();
    }

    @Override
    public void onPause() {
        super.onPause();
    }

    @Override
    public void onStop() {
        super.onStop();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    // 设置接口的方法
    public void setOnTitleClickListener(OnTitleClickListener onTitleClickListener) {
        this.onTitleClickListener = onTitleClickListener;
    }

    // 定义个接口的全局变量
    OnTitleClickListener onTitleClickListener;

    // 定义接口
    public interface  OnTitleClickListener{
        void onClick(String title);
    }

}
public class MainActivity extends AppCompatActivity implements ListFragment.OnTitleClickListener{

    public static final String BUTTON_TITLE = "button_title";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // setContentView(R.layout.activity_main);
        setContentView(R.layout.activity_main);
        findViewById(R.id.textView).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this, StaticLoadFragment.class));
            }
        });
        // 1.container 2.fragment 3.fragment-->container

        ListFragment fragment = ListFragment.newInstance("list");
        getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.listContainer, fragment)
                .commit();
        fragment.setOnTitleClickListener(this);
        // 一个fragment用一次,这里新建一个
        getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.detailContainer, ListFragment.newInstance("detail"))
                .commit();
        // 移除
//        getSupportFragmentManager()
//                .beginTransaction()
//                .remove(fragment)
//                .commit();
    }

    @Override
    public void onClick(String title) {
        setTitle(title);
    }
}

在Fragment被创建的时候,通过 fragment.setOnTitleClickListener(this) 将Activity传入到了Fragment中去,在Fragment中调用Activity的方法(这里就是onClick)

这里使用接口实现,更好的解耦

比如,在Fragment中定义

    MainActivity appCompatActivity;

    public void setAppCompatActivity(MainActivity appCompatActivity) {
        this.appCompatActivity = appCompatActivity;
    }

也可以,但是完全和这个Activity耦合在了一起

PageView

view_first.xml、view_second.xml、view_third.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="first"
        android:textSize="40sp"/>
RelativeLayout>


==========================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="second"
        android:textSize="40sp"/>
RelativeLayout>

=========================================

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="third"
        android:textSize="40sp"/>
RelativeLayout>
public class MainActivity extends AppCompatActivity{

    private ViewPager mViewPager;

    private int[] mLayoutIDs = {
      R.layout.view_first,
      R.layout.view_second,
      R.layout.view_third
    };
    private List mViews;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // setContentView(R.layout.activity_main);
        setContentView(R.layout.activity_main);
        mViewPager = (ViewPager) findViewById(R.id.view_pager);
        // 初始化数据
        mViews = new ArrayList<>();
        for (int index=0; index< mLayoutIDs.length; index++){
            mViews.add(getLayoutInflater().inflate(mLayoutIDs[index], null));
        }
        // 设置adapter
        mViewPager.setAdapter(mPagerAdapter);
    }

    PagerAdapter mPagerAdapter = new PagerAdapter() {
        @Override
        public int getCount() {
            return mLayoutIDs.length;
        }

        @Override
        public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
            return view == object;
        }


        @NonNull
        @Override
        public Object instantiateItem(@NonNull ViewGroup container, int position) {
            View child = mViews.get(position);
            container.addView(child);
            return child;
        }

        @Override
        public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
            container.removeView(mViews.get(position));
        }
    };
    
}

activity_main.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:layout_height="match_parent"
    tools:context="com.example.MainActivity"
    android:orientation="vertical">

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    androidx.viewpager.widget.ViewPager>
LinearLayout>

图片下面加点

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:layout_height="match_parent"
    tools:context="com.example.MainActivity"
    android:orientation="vertical">

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    androidx.viewpager.widget.ViewPager>

    <LinearLayout
        android:id="@+id/dot_layout"
        android:layout_width="120dp"
        android:layout_height="30dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="30dp"
        android:orientation="horizontal"/>


RelativeLayout>
public class MainActivity extends AppCompatActivity{

    private ViewPager mViewPager;

    private int[] mLayoutIDs = {
      R.layout.view_first,
      R.layout.view_second,
      R.layout.view_third
    };
    private List mViews;
    private ViewGroup mDotViewGroup;
    private List mDotViews = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // setContentView(R.layout.activity_main);
        setContentView(R.layout.activity_main);
        mViewPager = (ViewPager) findViewById(R.id.view_pager);
        mDotViewGroup = (ViewGroup) findViewById(R.id.dot_layout);
        // 初始化数据
        mViews = new ArrayList<>();
        for (int index=0; index< mLayoutIDs.length; index++){
            ImageView imageView = new ImageView(this);
            imageView.setImageResource(R.mipmap.ic_launcher);
            mViews.add(imageView);
            ImageView dot = new ImageView(this);
            dot.setImageResource(R.mipmap.ic_launcher);
            dot.setMaxWidth(100);
            dot.setMaxHeight(100);

            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(20, 20);
            layoutParams.leftMargin = 20;
            dot.setLayoutParams(layoutParams);
            dot.setEnabled(false);
            mDotViewGroup.addView(dot);
            mDotViews.add(dot);
        }
        // 设置adapter
        mViewPager.setAdapter(mPagerAdapter);
        mViewPager.setOffscreenPageLimit(4);
        mViewPager.setCurrentItem(0); // 设置第一页为当前页
        setDotViews(0);
        // 监听每页改变
        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            // 滚动
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            // 选中
            @Override
            public void onPageSelected(int position) {
                setDotViews(position);
            }

            // 滚动状态变化
            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
    }
    private void setDotViews(int position){
        for(int index=0; index){
            mDotViews.get(index).setImageResource(position == index? R.mipmap.star: R.mipmap.ic_launcher);
        }
    }
    PagerAdapter mPagerAdapter = new PagerAdapter() {
        @Override
        public int getCount() {
            return mLayoutIDs.length;
        }

        @Override
        public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
            return view == object;
        }


        @NonNull
        @Override
        public Object instantiateItem(@NonNull ViewGroup container, int position) {
            View child = mViews.get(position);
            container.addView(child);
            return child;
        }

        @Override
        public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
            container.removeView(mViews.get(position));
        }
    };
}

Fragment配置ViewPager

 创建Activity

activity_tab_viewpager.xml

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

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
LinearLayout>
public class TabViewPagerActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tab_viewpager);

        ViewPager viewPager = (ViewPager)findViewById(R.id.view_pager);
        viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                return TestFragment.newInstance(position);
            }

            @Override
            public int getCount() {
                return 4;
            }
        });
    }
}

创建Fragment

public class TestFragment extends Fragment {

    public static final String POSITION = "position";
    public static TestFragment newInstance(int position){
        TestFragment testFragment = new TestFragment();
        Bundle bundle = new Bundle();
        bundle.putInt(POSITION, position);
        testFragment.setArguments(bundle);
        return testFragment;
    }

    String mPostion;
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(getArguments() != null){
            mPostion = String.valueOf(getArguments().getInt(POSITION));
        }
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_test, null);
        TextView textView = (TextView)view.findViewById(R.id.text_view);
        textView.setText(mPostion);
        return view;
    }
}

fragment_test.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/text_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:textSize="36sp"
        android:layout_centerInParent="true"
        android:text="@string/aidata"
        android:gravity="center"/>

RelativeLayout>

实现底部导航

 使用TabHost + ViewPager

使用TabHost显然是为了使用底部tab标签,使用ViewPager是为了什么?为了 实现滑动功能。

 TabHost布局,必须有一个帧布局和一个TabWidget

即使帧布局在此案例中没用,也必须要,只需要将其 visibility设置为gone

activity_tab_viewpager.xml
<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        
        <androidx.viewpager.widget.ViewPager
            android:id="@+id/view_pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@id/tab_divider"/>

        <FrameLayout
            android:id="@+id/tabcontent"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone"
            android:layout_above="@id/tab_divider"/>

        <View
            android:id="@+id/tab_divider"
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#dfdfdf"
            android:layout_above="@id/tabs"/>

        <TabWidget
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:layout_alignParentBottom="true"/>
    RelativeLayout>
TabHost>
public class TabViewPagerActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tab_viewpager);

        Fragment[] fragments = new Fragment[]{
                TestFragment.newInstance("home"),
                TestFragment.newInstance("message"),
                TestFragment.newInstance("me")
        };

        ViewPager viewPager = (ViewPager)findViewById(R.id.view_pager);
        viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                return fragments[position];
            }

            @Override
            public int getCount() {
                return fragments.length;
            }
        });
    }
}
public class TestFragment extends Fragment {

    public static final String TITLE = "title";
    public static TestFragment newInstance(String title){
        TestFragment testFragment = new TestFragment();
        Bundle bundle = new Bundle();
        bundle.putString(TITLE, title);
        testFragment.setArguments(bundle);
        return testFragment;
    }

    private String mTitle;
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(getArguments() != null){
            mTitle = getArguments().getString(TITLE);
        }
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_test, null);
        TextView textView = (TextView)view.findViewById(R.id.text_view);
        textView.setText(mTitle);
        return view;
    }
}

下面添加最底部的按钮

<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/tab_host">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        
        <androidx.viewpager.widget.ViewPager
            android:id="@+id/view_pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@+id/tab_divider"/>

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone"
            android:layout_above="@+id/tab_divider"/>

        <View
            android:id="@+id/tab_divider"
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#dfdfdf"
            android:layout_above="@android:id/tabs"/>

        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:layout_alignParentBottom="true"
            android:showDividers="none"/>
    RelativeLayout>
TabHost>

图标

main_tab_icon_home
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:drawable="@drawable/tabbar_home_pressed"/>
    <item android:state_pressed="true" android:drawable="@drawable/tabbar_home_pressed"/>
    <item android:drawable="@drawable/tabbar_home"/>
selector>
main_tab_icon_message
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:drawable="@drawable/tabbar_msg_pressed"/>
    <item android:state_pressed="true" android:drawable="@drawable/tabbar_msg_pressed"/>
    <item android:drawable="@drawable/tabbar_msg"/>
selector>
main_tab_icon_me
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:drawable="@drawable/tabbar_my_pressed"/>
    <item android:state_pressed="true" android:drawable="@drawable/tabbar_my_pressed"/>
    <item android:drawable="@drawable/tabbar_my"/>
selector>
public class TabViewPagerActivity extends AppCompatActivity implements TabHost.TabContentFactory {

    public TabHost mTabHost;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tab_viewpager);

        // 初始化总布局
        mTabHost = (TabHost)findViewById(R.id.tab_host);
        mTabHost.setup();
        // 三个tab做处理
        int[] titleIDs = {R.string.home, R.string.message, R.string.me};
        int [] drawableIDs = {R.drawable.main_tab_icon_home, R.drawable.main_tab_icon_message, R.drawable.main_tab_icon_me};

        // 数据塞到视图里
        for (int index=0; index < titleIDs.length; index++){
            View view = getLayoutInflater().inflate(R.layout.main_tab_layout, null, false);
            ImageView icon = (ImageView)view.findViewById(R.id.main_tab_icon);
            TextView title = (TextView) view.findViewById(R.id.main_tab_txt);
            View tab = view.findViewById(R.id.tab_bg);
            icon.setImageResource(drawableIDs[index]);
            title.setText(titleIDs[index]);
            tab.setBackgroundColor(getResources().getColor(R.color.white));
            mTabHost.addTab(mTabHost.newTabSpec(getString(titleIDs[index]))
                    .setIndicator(view)
                    .setContent(this)
            );
        }

        // 三个fragment组成的viewpager
        final Fragment[] fragments = new Fragment[]{
                TestFragment.newInstance("home"),
                TestFragment.newInstance("message"),
                TestFragment.newInstance("me")
        };

        ViewPager viewPager = (ViewPager)findViewById(R.id.view_pager);
        viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                return fragments[position];
            }

            @Override
            public int getCount() {
                return fragments.length;
            }
        });
        // 添加监听,当滑动的时候下面的按钮出现变化
        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                if (mTabHost != null){
                    mTabHost.setCurrentTab(position);
                }
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
        // TAB动,viewpager也动
        mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
            @Override
            public void onTabChanged(String tabId) {
                if (mTabHost != null){
                    int position = mTabHost.getCurrentTab();
                    viewPager.setCurrentItem(position);
                }
            }
        });
    }

    @Override
    public View createTabContent(String tag) {
        View view = new View(this);
        view.setMinimumHeight(0);
        view.setMinimumWidth(0);
        return view;
    }
}
main_tab_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android:id="@+id/tab_bg"
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_centerInParent="true"
        android:orientation="vertical">
        <ImageView
            android:id="@+id/main_tab_icon"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:src="@mipmap/ic_launcher"
            android:layout_marginTop="4dp"/>
        <TextView
            android:id="@+id/main_tab_txt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/aidata"
            android:layout_marginTop="5dp"
            android:textColor="@color/color_main_tab_txt"/>
    LinearLayout>
    <ImageView
        android:visibility="gone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
RelativeLayout>

在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById()。不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化;而findViewById()是找xml布局文件下的具体widget控件(如Button、TextView等)。

具体作用: 1、对于一个没有被载入或者想要动态载入的界面,都需要使用LayoutInflater.inflate()来载入; 2、对于一个已经载入的界面,就可以使用Activiyt.findViewById()方法来获得其中的界面元素。 LayoutInflater 是一个抽象类,在文档中如下声明: public abstract class LayoutInflater extends Object 获得 LayoutInflater 实例的三种方式
1. LayoutInflater inflater = getLayoutInflater();//调用Activity的getLayoutInflater() 
2. LayoutInflater inflater = LayoutInflater.from(context);  
3. LayoutInflater inflater =  (LayoutInflater)context.getSystemService (Context.LAYOUT_INFLATER_SERVICE);

这三种方式最终本质是都是调用的Context.getSystemService()。

另外getSystemService()是Android很重要的一个API,它是Activity的一个方法,根据传入的NAME来取得对应的Object,然后转换成相应的服务对象。
传入的Name     返回的对象    说明
WINDOW_SERVICE    WindowManager    管理打开的窗口程序
LAYOUT_INFLATER_SERVICE    LayoutInflater    取得xml里定义的view
ACTIVITY_SERVICE    ActivityManager    管理应用程序的系统状态
POWER_SERVICE    PowerManger    电源的服务
ALARM_SERVICE    AlarmManager    闹钟的服务
NOTIFICATION_SERVICE    NotificationManager    状态栏的服务
KEYGUARD_SERVICE    KeyguardManager    键盘锁的服务
LOCATION_SERVICE    LocationManager    位置的服务,如GPS
SEARCH_SERVICE    SearchManager    搜索的服务
VEBRATOR_SERVICE    Vebrator    手机震动的服务
CONNECTIVITY_SERVICE    Connectivity    网络连接的服务
WIFI_SERVICE    WifiManager    Wi-Fi服务
TELEPHONY_SERVICE    TeleponyManager    电话服务

在Android APP中,所有的用户界面元素都是由View和ViewGroup的对象构成的。View是绘制在屏幕上的用户能与之交互的一个对象。而ViewGroup则是一个用于存放其他View(和ViewGroup)对象的布局容器! Android为我们提供了一个View和ViewGroup子类的集合,集合中提供了一些常用的输入控件(比如按钮和文本域)和各种各样的布局模式(比如线性或相对布局)


你的APP的用户界面上的每一个组件都是使用View和ViewGroup对象的层次结构来构成的,比如 图 1。每个ViewGroup都是要给看不见的用于组织子View的容器,而它的子View可能是输入控件 或者在UI上绘制了某块区域的小部件。有了层次树,你就可以根据自己的需要,设计简单或者复 杂的布局了(布局越简单性能越好)

 图 1.一个UI布局的层次结构的插图