分类 android UI 下的文章

Android TV中WebView的按键响应问题

软硬件环境

  • Macbook Pro MGX 72
  • Android studio 1.0.2
  • BesTV小红

问题场景

当布局中是一个WebView时,打开页面后,焦点就移到了WebView上,默认情况下,此时遥控器只响应返回键,如果需要响应其它键值(比如菜单键),这时该怎么做呢?本文就来解答这个问题。

应对方法

一般的键值处理是放在onKeyDown(int keyCode,KeyEvent keyevent)里处理的,不过在上述场景中,onKeyDown方法中接收不到菜单键,如果想让其也能够接收到,也不难,往下看。

webView = (WebView)findViewById(R.id.webView);

WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setUseWideViewPort(true);
webSettings.setLoadWithOverviewMode(true);

webView.setWebViewClient(new WebViewClient(){
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            //return super.shouldOverrideUrlLoading(view, url);
            return true;
        }

        @Override
        public boolean shouldOverrideKeyEvent(WebView webView,KeyEvent keyEvent) {
            //让onKeyDown来处理KeyEvent.KEYCODE_STAR,此处对应小红遥控器菜单键
            if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_STAR) {
                return true;
            } else {
                return false;
            }
        }
    }

Android应用的多语言支持

软硬件环境

  • Windows 10
  • Android studio 2.3.2
  • OTT BOx with android 5.1.1

前言

App开发测试完成后就面临着应用上架,除了国内的上架渠道,android阵营上架Google play我觉得是必不可少的。这样的话,中英文支持就成了必须的功能点了。本文就来实现这个功能。

设置不同语言的资源文件

如有必要,res文件夹下的像drawable、layout、values等都需要做不同语言的处理,这里仅以values为例

language_res

values-en和values-zh-rCN文件夹中的内容都一样values-en就是values-zh-rCN对应的英文翻译,如strings.xml文件内容如下

language_string

接下来就是如何使用对应资源,非常简答,以Toast为例

Toast.makeText(MainActivity.this, R.string.play_error, Toast.LENGTH_LONG).show();

系统当前的语言环境

这里仅处理中文、英文,如果还有其它语言,需要稍作修改

private boolean isZh() {
    Locale locale = getResources().getConfiguration().locale;
    String language = locale.getLanguage();
    if (language.endsWith("zh")) {
        return true;
    } else {
        return false;
    }
}

App内设置语言

//获取res资源对象
Resources resources = getResources();    
//获取设置对象
Configuration config = resources.getConfiguration();   
//获取屏幕参数:主要是分辨率,像素等
DisplayMetrics dm = resources.getDisplayMetrics(); 
//设置APP语言设置为英文
config.locale = Locale.ENGLISH;  
//设置完以后要刷新Activity才能及时生效
resources.updateConfiguration(config, dm);

资源文件夹后缀

给出一个常用的语言文件夹命名列表,方便查询

中文(中国):values-zh-rCN
中文(台湾):values-zh-rTW
中文(香港):values-zh-rHK
英语(美国):values-en-rUS
英语(英国):values-en-rGB
英文(澳大利亚):values-en-rAU
英文(加拿大):values-en-rCA
英文(爱尔兰):values-en-rIE
英文(印度):values-en-rIN
英文(新西兰):values-en-rNZ
英文(新加坡):values-en-rSG
英文(南非):values-en-rZA
阿拉伯文(埃及):values-ar-rEG
阿拉伯文(以色列):values-ar-rIL
保加利亚文:  values-bg-rBG
加泰罗尼亚文:values-ca-rES
捷克文:values-cs-rCZ
丹麦文:values-da-rDK
德文(奥地利):values-de-rAT
德文(瑞士):values-de-rCH
德文(德国):values-de-rDE
德文(列支敦士登):values-de-rLI
希腊文:values-el-rGR
西班牙文(西班牙):values-es-rES
西班牙文(美国):values-es-rUS
芬兰文(芬兰):values-fi-rFI
法文(比利时):values-fr-rBE
法文(加拿大):values-fr-rCA
法文(瑞士):values-fr-rCH
法文(法国):values-fr-rFR
希伯来文:values-iw-rIL
印地文:values-hi-rIN
克罗里亚文:values-hr-rHR
匈牙利文:values-hu-rHU
印度尼西亚文:values-in-rID
意大利文(瑞士):values-it-rCH
意大利文(意大利):values-it-rIT
日文:values-ja-rJP
韩文:values-ko-rKR
立陶宛文:valueslt-rLT
拉脱维亚文:values-lv-rLV
挪威博克马尔文:values-nb-rNO
荷兰文(比利时):values-nl-BE
荷兰文(荷兰):values-nl-rNL
波兰文:values-pl-rPL
葡萄牙文(巴西):values-pt-rBR
葡萄牙文(葡萄牙):values-pt-rPT
罗马尼亚文:values-ro-rRO
俄文:values-ru-rRU
斯洛伐克文:values-sk-rSK
斯洛文尼亚文:values-sl-rSI
塞尔维亚文:values-sr-rRS
瑞典文:values-sv-rSE
泰文:values-th-rTH
塔加洛语:values-tl-rPH
土耳其文:values--r-rTR
乌克兰文:values-uk-rUA
越南文:values-vi-rVN

Android中的service简介

软硬件环境

  • ubuntu kylin 14.04
  • 红米note增强版
  • Android studio 0.8.6

概述

Service就是Android系统中的服务。Service不像Activity,它无法直接和用户进行交互,必须由用户或者程序显式地启动。另一方面,Service的优先级比较高,这就使得当系统资源紧缺时,Service被销毁的机率非常低。一般来说,类似在当前系统交互中想继续处理其它数据类似的场景就会使用到Service,如想一边看电子书一边听音乐。

Service的生命周期

相比Activity的生命周期,Service的会简单很多

void onCreate();
int onStartCommand(Intent intent,int flags,int startId);//替换了原来的onStart(Intent intent);
void onDestroy();

Service从onCreate开始,到onDestroy结束,onStartCommand启动Service。如果Service已经启动,而我们再次去启动时,不会执行onCreate方法,而是直接去执行onStartCommand方法。如图所示:

上图列出了2种启动Service的方式,一种是通过startService,另一种是通过bindService。

Activity和Service通信实例

目标效果图如下

新建工程AndroidServiceDemo,Activity名称为AndroidServiceDemoActivity,然后在源码目录创建一个service文件AndroidServiceDemo.java,即Android studio中的右键-->New-->Service-->Service。

布局文件activity_android_service_demo.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".AndroidServiceDemoActivity">

<Button
    android:id="@+id/startButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:text="Start Service" />

<Button
    android:id="@+id/stopButton"
    android:layout_below="@+id/startButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:text="Stop Service" />

<TextView
    android:id="@+id/textFake"
    android:layout_below="@+id/stopButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

<Button
    android:id="@+id/bindButton"
    android:layout_below="@+id/textFake"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:text="Bind Service" />

<Button
    android:id="@+id/unbindButton"
    android:layout_below="@+id/bindButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:text="Unbind Service" />

</RelativeLayout>

AndroidManifest.xml文件由android studio自动生成,不需要改动,注意下service标签就可以了,每个service对应一组标签。

<service
    android:name=".AndroidServiceDemo"
    android:enabled="true"
    android:exported="true" >
</service>

接下来看看创建的service的代码AndroidServiceDemo.java

package com.macernow.djstava.androidservicedemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class AndroidServiceDemo extends Service {

    private static final String TAG = "AndroidServiceDemo";

    public AndroidServiceDemo() {
    }

    @Override
    public IBinder onBind(Intent intent){
        Log.e(TAG,"onBind... ...");

        return null;
    }

    @Override
    public void onCreate(){
        Log.e(TAG,"onCreate... ...");
        super.onCreate();
    }

    @Override
    public void onDestroy(){
        Log.e(TAG,"onDestroy... ...");
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent,int flags,int startId){
        Log.e(TAG,"onStartCommand... ...");
        return super.onStartCommand(intent,flags,startId);
    }
}

onBind方法需要返回一个IBinder对象,简单起见,这里直接返回null了。

最后看看Activity的相关代码AndroidServiceDemoActivity.java

package com.macernow.djstava.androidservicedemo;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
public class AndroidServiceDemoActivity extends Activity {
    private static final String TAG = "AndroidServiceDemoActivity";
    private static Button mStartButton,mStopButton,mBindButton,mUnbindButton;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_android_service_demo);

        mStartButton = (Button) findViewById(R.id.startButton);
        mStopButton = (Button) findViewById(R.id.stopButton);
        mBindButton = (Button) findViewById(R.id.bindButton);
        mUnbindButton = (Button) findViewById(R.id.unbindButton);

        mBindButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, "mBindButton... ...");
                bindService(new Intent(AndroidServiceDemoActivity.this,AndroidServiceDemo.class), mConnection, BIND_AUTO_CREATE);
            }
        });

        mStartButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, "mStartButton... ...");
                startService(new Intent(AndroidServiceDemoActivity.this,AndroidServiceDemo.class));
            }
        });

        mStopButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, "mStopButton... ...");
                stopService(new Intent(AndroidServiceDemoActivity.this,AndroidServiceDemo.class));
            }
        });

        mUnbindButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e(TAG, "mUnbindButton... ...");
                unbindService(mConnection);
            }
        });
    }

    ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(TAG,"onServiceConnected... ...");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG,"onServiceDisconnected... ...");
        }
    };

    @Override
    protected void onDestroy(){
        Log.e(TAG,"onDestroy... ...");
        unbindService(mConnection);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.android_service_demo, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

上面代码中出现了一个ServiceConnection类,并实现了onServiceConnected和onServiceDisconnected方法。一般来讲,bind service后的处理操作放在onServiceConnected方法中进行。而bindService和unbindService方法都是对ServiceConnection对象进行操作。

依次点击应用界面上的4个按钮,logcat中的打印如下

可以看到stopService和unbindService都是调用的onDestroy方法。

参考资料

1、http://developer.android.com/reference/android/app/Service.html
2、http://developer.android.com/guide/topics/manifest/service-element.html

Android JSON数据解析

软硬件环境

  • Macbook Pro MGX 72
  • Android Studio 1.3.2
  • Genymotion模拟器

前言

如今的APP很少有不跟服务器打交道的,其中在轻量级的通信交互中,JSON(JavaScript Object Notation)和XML,并称为客户端和服务端交互解决方案的倚天剑和屠龙刀,本文主要介绍JSON相关的知识。

JSON对象

JSON中对象包括在一对大括号里面,对象中的每一个item都是一个"key:value"数据对,数据对之间以逗号来分隔。JSON对象的key只能是String类型,value可能是其它类型如number,boolean,null。如下所示

{
    "Name" : "Alex",
    "Sex"  : "Male",
    "Age"  : "20",
}

JSON数组

JSON数组包括在一对中括号里面,每一个元素都是一个JSON对象,也是以逗号来分隔,示例如下

[
    {
    "Name" : "Alex",
    "Sex"  : "Male",
    "Age"  : "20",
    },
    {
    "Name" : "May",
    "Sex"  : "Female",
    "Age"  : "19",
    },
    {
    "Name" : "Mike",
    "Sex"  : "Male",
    "Age"  : "21",
    }
]

FastJSON的基本用法

FastJSON是alibaba公司开发出来的专门解析JSON的一个框架,根据他们自己的测试,速度非常快,效率非常高,而且没有之一。我们以从聚合数据网站上查询苏州城市天气预报的一个JSON数据为例来说明,获取的URL地址是http://v.juhe.cn/weather/index?format=2&cityname=%E8%8B%8F%E5%B7%9E&key=6f9276e4d79c5d102bbfb28717beba93。为确保数据源没有问题,可以在浏览器中打开URL,看看是否有数据。这里再介绍一款Mac下的工具JSON Accelerator,不但可以从网络上抓取,还可以添加http请求头信息,使用起来非常方便。

fastjson_01

创建工程

新建工程取名为FastJSONDemo,由于要访问网络,所以需要在AndroidManifest.xml中添加相应权限

<uses-permission android:name="android.permission.INTERNET" />

代码部分

网络请求部分,这里我们使用volley这个库,Google出品,使用简单。源码下载地址https://android.googlesource.com/platform/frameworks/volley/,jar包的下载地址http://download.csdn.net/detail/djstava/8793421。下载后把volley的库导入到工程中,UI的话,用了一个TextView来显示接收到的json数据

为了建立一个全局的请求队列,需要在实现一个继承自Application的子类,叫VolleyApplication

package com.djstava.fastjsondemo;
import android.app.Application;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;

/**
  • 包名称: com.djstava.fastjsondemo

    • 创建人: djstava

    • 创建时间: 15/9/23 下午3:44
      */
      public class VolleyApplication extends Application{
      public static RequestQueue requestQueue;

      @Override
      public void onCreate() {
      super.onCreate();

      requestQueue = Volley.newRequestQueue(getApplicationContext());

}
public static RequestQueue getVolleyQueue() {
    return requestQueue;
    }
}

然后在MainActivity中的onStart方法编写请求部分,然后在onStop方法中取消请求

private static final String JSON_URL = "http://v.juhe.cn/weather/index?format=2&cityname=%E8%8B%8F%E5%B7%9E&key=6f9276e4d79c5d102bbfb28717beba93";
//字段key是从聚合数据网站上申请过来的,请自行替换

@Override
protected void onStart() {
    super.onStart();

    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, JSON_URL, null,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject jsonObject) {
                    try {
                        textView.setText(jsonObject.toString());
                        Log.e(TAG,"result:" + jsonObject.getString("resultcode"));
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            },
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError volleyError) {
                    Log.e(TAG, volleyError.getMessage());
                }
            });

    jsonObjectRequest.setTag("fastjson");
    VolleyApplication.requestQueue.add(jsonObjectRequest);
}

@Override
protected void onStop() {
    super.onStop();

    VolleyApplication.requestQueue.cancelAll("fastjson");
}

别忘了在AndroiManifest.xml文件Application标签中加入

android:name=".VolleyApplication"

使用Genymotion模拟器运行程序,可以看到获取的数据

fastjson_02

为了方便读者查看,利用JSON Accelerator格式化一下

{
"result" : {
"sk" : {
  "humidity" : "58%",
  "wind_direction" : "西北风",
  "temp" : "26",
  "wind_strength" : "2级",
  "time" : "17:27"
},

"today" : {
  "temperature" : "22℃~27℃",
  "dressing_index" : "舒适",
  "dressing_advice" : "建议着长袖T恤、衬衫加单裤等服装。年老体弱者宜着针织长袖衬衫、马甲和长裤。",
  "uv_index" : "弱",
  "comfort_index" : "",
  "wind" : "东北风3-4 级",
  "weather" : "多云转阵雨",
  "city" : "苏州",
  "date_y" : "2015年09月24日",
  "week" : "星期四",
  "wash_index" : "不宜",
  "weather_id" : {
    "fa" : "01",
    "fb" : "03"
  },
  "travel_index" : "较适宜",
  "exercise_index" : "较适宜",
  "drying_index" : ""
},

"future" : [
  {
    "temperature" : "22℃~27℃",
    "weather_id" : {
      "fa" : "01",
      "fb" : "03"
    },
    "wind" : "东北风3-4 级",
    "week" : "星期四",
    "date" : "20150924",
    "weather" : "多云转阵雨"
  },
  {
    "temperature" : "21℃~26℃",
    "weather_id" : {
      "fa" : "03",
      "fb" : "01"
    },
    "wind" : "东北风3-4 级",
    "week" : "星期五",
    "date" : "20150925",
    "weather" : "阵雨转多云"
  },
  {
    "temperature" : "21℃~27℃",
    "weather_id" : {
      "fa" : "01",
      "fb" : "01"
    },
    "wind" : "东北风3-4 级",
    "week" : "星期六",
    "date" : "20150926",
    "weather" : "多云"
  },
  {
    "temperature" : "21℃~28℃",
    "weather_id" : {
      "fa" : "00",
      "fb" : "00"
    },
    "wind" : "东北风3-4 级",
    "week" : "星期日",
    "date" : "20150927",
    "weather" : "晴"
  },
  {
    "temperature" : "22℃~28℃",
    "weather_id" : {
      "fa" : "01",
      "fb" : "01"
    },
    "wind" : "东风3-4 级",
    "week" : "星期一",
    "date" : "20150928",
    "weather" : "多云"
  },
  {
    "temperature" : "22℃~28℃",
    "weather_id" : {
      "fa" : "01",
      "fb" : "03"
    },
    "wind" : "东风3-4 级",
    "week" : "星期二",
    "date" : "20150929",
    "weather" : "多云转阵雨"
  },
  {
    "temperature" : "20℃~25℃",
    "weather_id" : {
      "fa" : "04",
      "fb" : "04"
    },
    "wind" : "东南风4-5 级",
    "week" : "星期三",
    "date" : "20150930",
    "weather" : "雷阵雨"
    }
    ]
  },

  "resultcode" : "200",

  "reason" : "successed!",

  "error_code" : 0
}

接下来该轮到fastjson登场了,,先到http://repo1.maven.org/maven2/com/alibaba/fastjson/下载对应版本的jar包,或者到https://github.com/alibaba/fastjson下载源码,再导入到工程中。

JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, JSON_URL, null,
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject jsonObject) {
                    try {
                        textView.setText(jsonObject.toString());

                        com.alibaba.fastjson.JSONObject jsonObject1 = JSON.parseObject(jsonObject.toString());

                        for (Map.Entry<String, Object> entry : jsonObject1.entrySet()) {
                            System.out.println(entry.getKey() + ":" + entry.getValue());
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError volleyError) {
            Log.e(TAG, volleyError.getMessage());
        }
    });

fastjson_03

这样,简单的数据解析就完成了。

何为JavaBean?

JavaBean是符合某种规范的java组件,也就是java类,它必须满足如下特性:

  • 有一个无参数的默认构造函数
  • 有get和set方法

我们把公司员工抽象成一个类,然后利用fastjson来解析

package com.djstava.fastjsondemo;
/**
 * 包名称: com.djstava.fastjsondemo
 * 创建人: djstava
 * 创建时间: 15/9/28 上午11:07
 */
public class Employee {

    private int num;
    private String name;
    private int age;

    public Employee(int num, String name, int age) {
        this.num = num;
        this.name = name;
        this.age = age;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getNum() {

        return num;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

在Android Studio中,可以自动生成get、set、toString这些方法,Code->Generate,快捷键是Command + N。

fastjson_04

Employee employee  = new Employee(1,"djstava",20);
Log.e(TAG,JSON.toJSONString(employee));

fastjson_05

可以看出输出的json格式与我们类中定义的属性的顺序不一致,其实没有关系,json都是通过key去获取其对应的value的。

如果仅仅是想解析JavaBean类中某几个字段时,可以使用SimplePropertyPreFilter这个类来实现,将需要解析的字段添加进来,如将Employee类中的"num"和"name"解析出来

SimplePropertyPreFilter simplePropertyPreFilter = new SimplePropertyPreFilter(Employee.class,"num","name");
Log.e(TAG,JSON.toJSONString(employee,simplePropertyPreFilter));

fastjson_06

源码下载

http://download.csdn.net/detail/djstavav/9144789

参考文献

1、http://www.json.org/
2、https://github.com/alibaba/fastjson/wiki
3、https://www.juhe.cn/docs/api/id/39

Android中的ViewPager使用详解

软硬件环境

  • Android studio 2.1.3
  • 坚果手机 5.1.1

前言

ViewPager是android中进行View切换的一个控件。它是一个使用率非常高的控件,像app初次使用时的引导页面。本文将来学习一下这个控件以及相关的一些内容。

ViewPager的使用

要使用ViewPager,一般需要进行如下步骤

  1. 主布局中加入ViewPager
  2. 确定切换子View的布局
  3. 重写PagerAdapter的几个方法
  4. 给ViewPager设置adapter

主布局layout_main.xml

MainActivity的布局文件,加入ViewPager控件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.xugaoxiang.viewpagerdemo.MainActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </android.support.v4.view.ViewPager>
</LinearLayout>

layout_tab*.xml

子View的布局文件,只包含一个ImageView。我这里设置了5个切换的View,准备了5张美女图片,其它几个子View的布局跟这个差不多,只有图片不一样,这里就不再写了,自己补全吧。

<?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="match_parent">

    <ImageView
        android:src="@drawable/beauty1"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

MainActivity.java文件

package com.xugaoxiang.viewpagerdemo;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private ViewPager viewPager;
    private List<View> views;

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

        viewPager = (ViewPager) findViewById(R.id.viewPager);
        LayoutInflater layoutInflater = getLayoutInflater();

        views = new ArrayList<View>();
        views.add(layoutInflater.inflate(R.layout.layout_tab1,null));
        views.add(layoutInflater.inflate(R.layout.layout_tab2,null));
        views.add(layoutInflater.inflate(R.layout.layout_tab3,null));
        views.add(layoutInflater.inflate(R.layout.layout_tab4,null));
        views.add(layoutInflater.inflate(R.layout.layout_tab5,null));

        PagerAdapter pagerAdapter = new PagerAdapter() {
            @Override
            public int getCount() {
                return views.size();
            }

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

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

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
//                return super.instantiateItem(container, position);
                container.addView(views.get(position));
                return views.get(position);
            }
        };

        viewPager.setAdapter(pagerAdapter);
    }
}

初始化一个List用来存放需要切换的view,然后实例化PagerAdapter并重写getCount()、isViewFromObject()、destroyItem()和instantiateItem()这4个方法。运行下这个工程

viewpager_01

PagerAdapter中需要重写的几个函数

现在回头再看看PagerAdapter需要重写的4个方法

  • getCount 返回当前有效子view的个数
  • destroyItem 将制定的view从container中移除
  • instantiateItem 将视图添加到container中,并将当前视图作为key进行返回
  • isViewFromObject 判断instantiateItem方法返回来的key与视图是不是同一个

注意到上面方法解释中谈到了一个新的概念,key。简单来讲,key是视图的标识,根据key就可以找到其对应的view。在我们重写instantiateItem这个方法时,我们将View作为key返回,当然你也可以将position作为key进行返回。这样的话,对应地在重写isViewFromObject方法时,应该先根据position找到view再和参数1的View尽心比较,一致返回ture,否则返回false。

PagerTitleStrip和PagerTabStrip

PagerTitleStrip和PagerTabStrip都是用来实现标题栏的,它们的写法完全一样,区别在于

  1. PagerTabStrip方式的标题栏下有根下划线
  2. PagerTabStrip方式的标题栏响应点击事件,可以切换到对应的view

layout_mail.xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.xugaoxiang.viewpagerdemo.MainActivity">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_gravity="center"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v4.view.PagerTitleStrip
            android:id="@+id/pagerTitle"
            android:layout_gravity="top"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
        </android.support.v4.view.PagerTitleStrip>

    </android.support.v4.view.ViewPager>
</LinearLayout>

属性android:layout_gravity="top"指定了标题栏设置在了顶部,当然你也可以将它设置在底部。

MainActivity.java中实例化PagerAdapter时,需要再重写一个方法,getPageTitle

package com.xugaoxiang.viewpagerdemo;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private ViewPager viewPager;
    private List<View> views;
    private List<String> titleList;

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

        viewPager = (ViewPager) findViewById(R.id.viewPager);
        LayoutInflater layoutInflater = getLayoutInflater();

        views = new ArrayList<View>();
        views.add(layoutInflater.inflate(R.layout.layout_tab1,null));
        views.add(layoutInflater.inflate(R.layout.layout_tab2,null));
        views.add(layoutInflater.inflate(R.layout.layout_tab3,null));
        views.add(layoutInflater.inflate(R.layout.layout_tab4,null));
        views.add(layoutInflater.inflate(R.layout.layout_tab5,null));

        titleList = new ArrayList<String>();
        titleList.add("第一页Tab");
        titleList.add("第二页Tab");
        titleList.add("第三页Tab");
        titleList.add("第四页Tab");
        titleList.add("第五页Tab");

        PagerAdapter pagerAdapter = new PagerAdapter() {
            @Override
            public int getCount() {
                return views.size();
            }

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

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

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
//                return super.instantiateItem(container, position);
                container.addView(views.get(position));
                return views.get(position);
            }

            @Override
            public CharSequence getPageTitle(int position) {
//                return super.getPageTitle(position);
                return titleList.get(position);
            }
        };

        viewPager.setAdapter(pagerAdapter);
    }
}

PagerTitleStrip的效果

viewpager_02

PagerTabStrip的效果

viewpager_03

循环滑动

前面的ViewPager当滑动到第一个的时候,再想往左滑就滑不动了;当滑动到最后一个的时候,再想往右滑也滑不懂了。如果想实现上述效果,需要重写PagerAdapter的几个方法。

        PagerAdapter pagerAdapter = new PagerAdapter() {

            @Override
            public int getCount() {
                return Integer.MAX_VALUE;
            }

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

            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
//                super.destroyItem(container, position, object);
                container.removeView(views.get(position % views.size()));
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
//                return super.instantiateItem(container, position);
                container.addView(views.get(position % views.size()));
                return views.get(position % views.size());
            }

            @Override
            public CharSequence getPageTitle(int position) {
//                return super.getPageTitle(position);
                return titleList.get(position % views.size());
            }
        };

viewpager_04

本文源码下载

  • http://download.csdn.net/detail/djstavav/9614782