1.Service 向Activity发送广播,更新UI
一个小的案例,简单的模拟的耗时工作,但是思路确实很常用的。
一个按钮,一个textview,实现textview一秒更新一次。拓展方向实现了暂停和继续。
在android中的主线程也就是UI线程,UI线程中才可以操作界面元素。在主线程中执行耗时操作,会造成UI阻塞,导致ANR;在非主线程中更新UI,会直接报错。
点击按钮,开启一个服务,然后在service中进行耗时的操作,每隔一秒用广播发送到activity中。service中开启的线程是不能更新UI的,所以就需要service通过广播发送数据到activity,然后activity取出数据,进行ui的更新。
后来我自己又想实现暂停和继续,一开始,觉得应该暂停服务,在重新开启服务,这样不合适,后来就像将线程暂停和继续执行就可以了。
我通过activity中的按钮,向service中发送广播,在service中接收到广播,然后执行相应的暂停和继续操作。
首先,我想到的是wait()和notifyAll()方法。所以,我直接调用了wait()方法,报错了。错误信息:
<p>AndroidRuntime(2329): java.lang.IllegalMonitorStateException: object not locked by thread before wait()</p>
字面意思就能看出,在调用wait()前需要锁定locked。
所以,在调用wait()和notifyAll()前,需要先synchronized锁定,类似于下面这种
syncronized(this) { //把wait代码放在synchronized块中,锁线程自己
wait(1000); //锁一定的时间,要不然没有notify就一直wait了
}
因为,wait()针对的不是Thread/Runnable,而是针对的对象。
假设某个Object lock = new Object();
线程1(比如消费者线程)调用lock.wait()方法后,线程1就停下,直到其他某个线程(比如生产者线程)调用了lock.notify()或者lock.notifyAll();唤醒一个或者多个等待lock被唤醒的线程(此例中的线程1)。
调用wait之前,需要对lock同步synchronized (lock) {...}
private String control = "";
然后在synchronized中使用。这个control本身并没有意义,只是随便一个对象而已,因为wait()和notify()之前,需要锁定对象,而他们又必须保证是同一个对象,所以就随便找了一个对象,保持一致性。否则就会报错。
直接上代码
MainActivity.java
package com.example.servicesendreceivertoactivity;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
public Button button;
public TextView textView;
public Intent serviceIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button);
textView = (TextView) findViewById(R.id.textView);
// 静态注册广播,过滤"niejianjian"这个广播
IntentFilter filter = new IntentFilter();
filter.addAction("niejianjian");
registerReceiver(njjReceiver, filter);
serviceIntent = new Intent(getApplicationContext(), MyService.class);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (button.getText().toString().equals("开始计时")) {
button.setText("暂停计时");
// 开启服务
startService(serviceIntent);
} else if (button.getText().toString().equals("暂停计时")) {
button.setText("继续计时");
// 向service发送暂停的广播
Intent intent = new Intent();
intent.setAction("niejianjian.pause");
sendBroadcast(intent);
} else {
button.setText("暂停计时");
// 向service发送继续的广播
Intent intent1 = new Intent();
intent1.setAction("niejianjian.resume");
sendBroadcast(intent1);
}
}
});
}
BroadcastReceiver njjReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// 获得接受到的数字,并进行设置
int count = intent.getIntExtra("Count", 0);
textView.setText("当前时间是: " + count);
}
};
}
MyService.java
package com.example.servicesendreceivertoactivity;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
int count = 0;
IntentFilter filter;
MyThread myThread;
Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 1:
myThread.setSuspend(true);
break;
case 2:
myThread.setSuspend(false);
break;
default:
break;
}
};
};
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
// 初始化线程,并且start开启线程
myThread = new MyThread();
myThread.start();
// 设置需要过滤的广播,并注册
filter = new IntentFilter();
filter.addAction("niejianjian.pause");
filter.addAction("niejianjian.resume");
registerReceiver(serReceiver, filter);
}
public BroadcastReceiver serReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String actionStr = intent.getAction();
if (actionStr.equals("niejianjian.pause")) {
handler.sendEmptyMessage(1);
} else if (actionStr.equals("niejianjian.resume")) {
handler.sendEmptyMessage(2);
}
}
};
public class MyThread extends Thread {
private boolean suspend = false;
private String control = ""; // 只是需要一个对象而已,这个对象没有实际意义
public void setSuspend(boolean suspend) {
if (!suspend) {
synchronized (control) {
control.notifyAll();
}
}
this.suspend = suspend;
}
public boolean isSuspend() {
return this.suspend;
}
@Override
public void run() {
super.run();
while (true) {
synchronized (control) {
if (suspend) {
try {
control.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 执行发送广播,传递count,实现计时的模块,每秒发送一次
*/
count++;
Intent intent = new Intent();
intent.setAction("niejianjian");
intent.putExtra("Count", count);
sendBroadcast(intent);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 这个方法只是用来单纯的实现计时,并不能实现暂停功能
*/
public Thread myThread11 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
count++;
Intent intent = new Intent();
intent.setAction("niejianjian");
intent.putExtra("Count", count);
sendBroadcast(intent);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
activity_main.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"
tools:context="${relativePackage}.${activityClass}" >
<Button
android:id="@+id/button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="开始计时" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="jishi"
android:textSize="30sp" />
</RelativeLayout>
AndroidManifest.xml中注册一下服务
<service android:name="com.example.servicesendreceivertoactivity.MyService" >
</service>
service的特点:
没有用户界面,
比activity的优先级高,不会请轻易的被android系统终止
即使service被系统终止,在系统资源恢复后,service也能自动回复运行状态
可用于IPC,解决两个不通的android应用程序之间的调用和通信问题。
2.多进程模式
android对单个应用所使用的最大内存做了限制,可以利用多进程模式增大一个应用可使用的内存。
android中使用多进程的方法:
1).给四大组件在AndroidManifest.xml中指定android:process属性。
2).非常规方法:通过JNI在native层去fork一个新的进程。
下面是个简单的案例:<activity
android:name="com.example.processtestdemo.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.processtestdemo.SecondActivity"
android:process=":njj"
android:label="@string/app_name" >
</activity>
<activity
android:name="com.example.processtestdemo.ThridActivity"
android:process="com.example.njj"
android:label="@string/app_name" >
</activity>
3个activity,并通过android:process属性来指定他们的进程。当activity启动的时候,就会创建相应的进程。
分别启动之后,可以通过DDMS查看
也可以在cmd中查看 abd shell ——> adb shell ps | grep com.example 后面 | 之后的属于过滤信息,可以不加。
我们的SecondActivity和ThridActivity的android:process属性的值分别是“:njj” 和”com.example.njj“。
首先,”:“有特殊的含义,它是值当前的进程名前面加上当前的包名,这是一个简写的方法。对于ThridActivity的写法来说,是一种完整的命名方式。
其次,”:“开头的进程属于当前应用的私有进程,其他应用的组件不可以和它泡在同一个进程中,而不是以”:“开头的进程属于全局的进程,其他应用可以通过ShareUID方式和它跑在同一个进程中。
UID:Android系统会给每个应用分配一个唯一的UID,具有相同的UID的应用,才能共享数据。两个应用通过ShareUID跑在同一个进程中是有要求的,需要这两个应用有相同的ShareUID和签名相同才可以。
多进程模式也会遇到一些问题,例如我们随便新建一个Contance.java类,其中有一个public静态变量
public class Contance {
public static int tes = 1;
}
在MainAcitity中将Contance.tes修改为2,打印出这个值后再跳转到SecondActivity中再打印一遍tes的值,会发现,在SecondActivity中仍然为1,也就是修改没有生效。但是如果把SecondAcitity清单文件中的process删除掉,就会打印出修改后的值。这就是多进程之间存在的一些问题。
上面的SecondActivity运行在一个单独的进程中。Android为每一个应用分配一个独立的虚拟机,或者说为每个进程分配一个独立的虚拟机,不同的的虚拟机在内存分配上占用不同的地址控件,这就导致不同的进程访问同一个类的对象会产生多分副本。简单的说就是自己处理好自己的事。
一般来说,使用多进程会造成如下的几个方面的问题:
1) 静态成员和单例模式完全失效
2) 线程同步机制完全失效
3) SharedPreferences的可靠性下降
4) Application会多次创建
第一个已经分析过了,对于第二个问题类似,既然已经不是同一块内存了,那么不管是锁对象还是锁全局类都无法保证线程同步,因为不同进程锁的不是同一个对象。第三个问题,SharedPreferences不支持两个进程同时去执行写操作,会有一定的几率数据导致数据丢失。第四个问题就是一个组件跑在一个新的进程中,由于系统要创建新的进程同时分配独立的虚拟机,所以这个过程就相当于启动一个应用的过程。
运行在同一个进程中的组件属于同一个虚拟机和同一个Application的,然后添加自己的Application来测试:
package com.example.processtestdemo;
import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
public class MyApplication extends Application {
String processName = null;
@Override
public void onCreate() {
super.onCreate();
getProcessName();
System.out.println("application start , process name = " + processName);
}
public String getProcessName() {
ActivityManager am = (ActivityManager) getApplicationContext()
.getSystemService(Context.ACTIVITY_SERVICE);
int myPid = android.os.Process.myPid();
for (ActivityManager.RunningAppProcessInfo runningPro : am
.getRunningAppProcesses()) {
if (runningPro.pid == myPid) {
processName = runningPro.processName;
}
}
return processName;
}
}
然后在清单文件的application中添加name属性
android:name="MyApplication"
分别点开三个Activity,打印如下log:
11-25 07:25:09.319: I/System.out(1272): application start , process name = com.example.processtestdemo
11-25 07:25:11.743: I/System.out(1288): application start , process name = com.example.processtestdemo:njj
11-25 07:25:13.775: I/System.out(1305): application start , process name = com.example.njj
根据log我们可以看出,不同的进程,分别创建一次Application。
3.类似于android通讯录的搜索功能,自动提示,快速定位
案例是有一个数据库文件,有几千个单词,每个都包含中文和英文。
1).当输入ab的时候,会自动提示全部以ab开头的单词,罗列出来。
2).还有就是,当输入ab的时候,会自动定位到以ab开头的第一个item。
资源下载:http://download.csdn.net/detail/u012975370/9367132
上部分代码:
MainActivity.java:
package com.example.autocompleteedittext;
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CursorAdapter;
import android.widget.TextView;
public class MainActivity extends Activity implements TextWatcher {
private AutoCompleteTextView auto_text;
private Util util;
public SQLiteDatabase database;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
util = new Util();
// 加载数据库的数据,放入本地。增加读取速度
util.initList(MainActivity.this);
database = util.getDatabase(MainActivity.this);
auto_text = (AutoCompleteTextView) findViewById(R.id.auto_text);
auto_text.addTextChangedListener(this);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, TwoActivity.class);
startActivity(intent);
}
});
}
public class MyAdapter extends CursorAdapter {
@Override
public CharSequence convertToString(Cursor cursor) {
return cursor == null ? "" : cursor.getString(cursor
.getColumnIndex("_id"));
}
public MyAdapter(Context context, Cursor c, boolean autoRequery) {
super(context, c, autoRequery);
}
private void setView(View view, Cursor cursor) {
TextView tView = (TextView) view;
tView.setText(cursor.getString(cursor.getColumnIndex("_id")));
tView.setTextSize(18);
tView.setPadding(15, 10, 10, 15);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = new TextView(MainActivity.this);
setView(view, cursor);
return view;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
setView(view, cursor);
}
}
@Override
public void afterTextChanged(Editable s) {
Cursor cursor;
// 获取输入的内容的byte数
byte[] bytes = s.toString().getBytes();
int m = bytes.length;
// 输入内容的长度
int n = s.length();
if (m == n) { // 输入的是英文字母
cursor = database.rawQuery(
"select english as _id from engtoch where english like ?",
new String[] { s.toString() + "%" });
} else { // 输入的中文
cursor = database.rawQuery(
"select chinese as _id from t_words where chinese like ?",
new String[] { s.toString() + "%" });
}
MyAdapter myAdapter = new MyAdapter(MainActivity.this, cursor, true);
auto_text.setAdapter(myAdapter);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
}
TwoActivity.java:
package com.example.autocompleteedittext;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Base64;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
public class TwoActivity extends Activity {
ListView listView;
EditText editText;
WordListAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_two);
listView = (ListView) findViewById(R.id.listView);
adapter = new WordListAdapter(TwoActivity.this, Contance.list);
System.out.println("list.size" + Contance.list.size());
listView.setAdapter(adapter);
editText = (EditText) findViewById(R.id.editText);
editText.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
@Override
public void afterTextChanged(Editable s) {
int topPosition = 0;
for (int i = 0; i < Contance.list.size(); i++) {
WordBean words = Contance.list.get(i);
// 判断有没有那个字符串是以输入的内容开头的
if (words.getEnglish().startsWith(
editText.getText().toString())) {
topPosition = i;
break;
}
}
// 将列表移动到指定的position处
listView.setSelection(topPosition);
adapter.notifyDataSetInvalidated();
}
});
}
public class WordListAdapter extends BaseAdapter {
Context mContext;
List<WordBean> mList = new ArrayList<WordBean>();
LayoutInflater inflater;
public WordListAdapter(Context context, List<WordBean> list) {
this.mContext = context;
this.mList = list;
inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return mList.size();
}
@Override
public Object getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.wordslist_item, null);
holder.chinese = (TextView) convertView
.findViewById(R.id.tv_chinese);
holder.english = (TextView) convertView
.findViewById(R.id.tv_english);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.chinese.setText(mList.get(position).getChinese());
holder.english.setText(mList.get(position).getEnglish());
return convertView;
}
}
class ViewHolder {
TextView english;
TextView chinese;
}
}
Util.java:
package com.example.autocompleteedittext;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
public class Util {
public void initList(final Context context) {
new Thread(new Runnable() {
@Override
public void run() {
Contance.list = getList(context);
System.out.println("list.size = " + Contance.list.size());
}
}).start();
}
public List<WordBean> getList(Context context) {
List<WordBean> list = new ArrayList<WordBean>();
Cursor cursor = getDatabase(context).rawQuery("select * from engtoch",
null);
cursor.moveToFirst();
int i = 0;
while (cursor.moveToNext()) {
System.out.println("move = " + i++);
String english = cursor.getString(cursor.getColumnIndex("english"));
String chinese = cursor.getString(cursor.getColumnIndex("chinese"));
WordBean word = new WordBean();
if (!(english == null) && !(chinese == null)) {
word.setEnglish(english);
word.setChinese(chinese);
list.add(word);
}
}
// while (!(cursor.getPosition() > 3785)) {
// System.out.println("move = " + i++);
// String english = cursor.getString(cursor.getColumnIndex("english"));
// String chinese = cursor.getString(cursor.getColumnIndex("chinese"));
//
// WordBean word = new WordBean();
// word.setEnglish(english);
// word.setChinese(chinese);
// list.add(word);
//
// cursor.moveToNext();
// }
return list;
}
/**
* 获得一个SQLiteDatabase对象
*/
public SQLiteDatabase getDatabase(Context context) {
// 文件的绝对路径
String dbFilePath = Contance.DATABASE_PATH + "/"
+ Contance.DATABASE_NAME;
/*
* 从raw文件夹下复制到sd下
*/
try {
File file = new File(Contance.DATABASE_PATH);
if (!file.exists()) {
file.mkdirs();
}
File file2 = new File(file, Contance.DATABASE_NAME);
if (!file2.exists()) {
file2.createNewFile();
}
// 获得封装dictionary.db文件的InputStream对象
InputStream iStream = context.getResources().openRawResource(
R.raw.dictionary);
FileOutputStream fos = new FileOutputStream(dbFilePath);
byte[] buff = new byte[8192];
int count = 0;
while ((count = iStream.read(buff)) != -1) {
fos.write(buff, 0, count);
}
fos.close();
iStream.close();
} catch (IOException e) {
e.printStackTrace();
}
// 打开数据库文件
SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(
dbFilePath, null);
return database;
}
}
package com.example.autocompleteedittext;
import java.util.List;
import android.os.Environment;
public class Contance {
public static List<WordBean> list;
public final static String DATABASE_NAME = "dictionary.db";
public final static String DATABASE_PATH = Environment
.getExternalStorageDirectory().getAbsolutePath() + "/dictionary";
}
WordsBean.java:
package com.example.autocompleteedittext;
public class WordBean {
private String english;
private String chinese;
public WordBean() {
}
public WordBean(String english, String chinese) {
this.english = english;
this.chinese = english;
}
public String getEnglish() {
return english;
}
public void setEnglish(String english) {
this.english = english;
}
public String getChinese() {
return chinese;
}
public void setChinese(String chinese) {
this.chinese = chinese;
}
}
4.Activity之间传递ArrayList
传递的MainActivity.java
package com.example.activity_arraylist;
import java.util.ArrayList;
import java.util.Iterator;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Serializable 传递
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ArrayList<MyClass> arrayList = new ArrayList<MyClass>();
for (int i = 0; i < 10; i++) {
MyClass myClass = new MyClass();
myClass.userName = "a->" + i;
myClass.psw = "b->" + i;
myClass.age = 20 + i;
arrayList.add(myClass);
}
Intent intent = new Intent();
intent.putExtra("key", arrayList);
intent.setClass(MainActivity.this, ResultActivity.class);
startActivity(intent);
}
});
// Parcelable 传递
Button button2 = (Button) findViewById(R.id.button2);
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ArrayList<MyClass2> arrayList = new ArrayList<MyClass2>();
for (int i = 0; i < 10; i++) {
MyClass2 myClass2 = new MyClass2();
myClass2.userName = "a->" + i;
myClass2.psw = "b->" + i;
myClass2.age = 20 + i;
arrayList.add(myClass2);
}
Intent intent = new Intent();
intent.putExtra("key", arrayList);
intent.setClass(MainActivity.this, ResultActivity2.class);
startActivity(intent);
}
});
}
}
1).使用Serializable方法
将类的实例序列化然后再做存储或者传输在JAVA中较为常见。
a.一个自定义类,实现了Serialization接口。
import java.io.Serializable;
public class MyClass implements Serializable {
private static final long serialVersionUID = 1L;
public String userName;
public String psw;
public int age;
}
b.接受的ResultActivity.java
public class ResultActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.result_main);
ArrayList<MyClass> arrayList = (ArrayList<MyClass>) getIntent()
.getSerializableExtra("key");
String result = "";
for (MyClass myClass : arrayList) {
result += (myClass.userName + "--" + myClass.psw + "--"
+ myClass.age + "\n");
}
TextView textView = (TextView) findViewById(R.id.textview);
textView.setText(result);
}
}
2).使用Parcelable方法
Android内存受限,迫使其封装了Parcel容器来代替Serializale方法
a.一个自定义类,实现了Parcelable接口
package com.example.activity_arraylist;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Parcel类:封装数据的容器,封装后的数据可以通过intent或者IPC传递
* Parcelable接口:自定义类继承该接口后,其实例化后能够被写入Paecel或从Parcel中恢复
* 如果某个类实现了该接口,那么它的对象实例可以写入Parcel中,并且能够从中恢复,并且这个类必须要有一个static的feld,
* 并且名称要为CREATOR,这个field是某个实现了Parcelable.Creator接口类的对象实例。
*/
public class MyClass2 implements Parcelable {
public String userName;
public String psw;
public int age;
// 静态的Parcelable.Creator接口
public static final Parcelable.Creator<MyClass2> CREATOR = new Creator<MyClass2>() {
// 创建出类的实例,并从Parcel中获取数据进行实例化
@Override
public MyClass2 createFromParcel(Parcel source) {
MyClass2 myClass2 = new MyClass2();
myClass2.userName = source.readString();
myClass2.psw = source.readString();
myClass2.age = source.readInt();
return myClass2;
}
@Override
public MyClass2[] newArray(int size) {
return new MyClass2[size];
}
};
@Override
public int describeContents() {
return 0;
}
// 将数据写入外部提供的Parcel中
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(userName);
dest.writeString(psw);
dest.writeInt(age);
}
}
b.接受的ResultActivity2.java
package com.example.activity_arraylist;
import java.util.ArrayList;
import java.util.Iterator;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
public class ResultActivity2 extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.result_main);
ArrayList<MyClass2> arrayList = (ArrayList<MyClass2>) getIntent()
.getSerializableExtra("key");
String result = "";
for (MyClass2 myClass2 : arrayList) {
result += (myClass2.userName + "---" + myClass2.psw + "---"
+ myClass2.age + "\n");
}
TextView textView = (TextView) findViewById(R.id.textview);
textView.setText(result);
}
}
5.自定义View
自定义View的步骤:
1.自定义View属性。
2.在View的构造方法中获取我们自定义的属性
3.重写onMeasure方法(非必须)
4.重写onDraw。
1.自定义View属性。首先在res/values下建立一个attrs.xml文件,在里面定义我们的属性和声明我们的整个样式。
1.<?xml version="1.0" encoding="utf-8"?>
2.<resources>
3.
4. <attr name="titleText" format="string" />
5. <attr name="titleTextColor" format="color" />
6. <attr name="titleTextSize" format="dimension" />
7.
8. <declare-styleable name="CustomTitleView">
9. <attr name="titleText" />
10. <attr name="titleTextColor" />
11. <attr name="titleTextSize" />
12. </declare-styleable>
13.
14.</resources>
我们定义了字体、字体颜色、字体大小。Format是该属性的属性值。
自定义View的步骤:
1.自定义一个CustomView(extends View)类
2.编写values/attrs.xml,在其中编写styleable和item等标签元素
3.在布局文件中customView使用自定义的属性(注意namespace)
4.在CustomView的构造方法中通过TypedArray获取。
http://blog.csdn.net/jdsjlzx/article/details/43452927
http://www.androidchina.net/2192.html
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:njjcustom="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.jian.myapplication.CustomViewNjj
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:padding="10dp"
njjcustom:titleText="3712"
njjcustom:titleTextColor1="#2635ff"
njjcustom:titleTextSize="50sp" />
</RelativeLayout>
CustomViewNjj.java
package com.example.jian.myapplication;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import java.lang.reflect.Array;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
/**
* 如果系统中已经有了语义比较明确的属性,我们还可以引用吗(比如njj:text和android:text)。
* 可以。直接在attrs.xml中使用android:text属性。<attr name="android:text" />
* 使用已经定义好的属性,不需要去添加format属性。(声明和使用的差别就是有没有format)
* 然后在类中这么获取:ta.getString(R.styleable.test_android_text);
* 布局文件中直接android:text="@string/hello_world"即可。
* <p/>
* 参考文章:http://www.androidchina.net/2192.html
*/
public class CustomViewNjj extends View {
private static final String TAG = "NieJianJian_Log";
private String mTitleText;
private int mTitleTextColor;
private int mTitleTextSize;
private Rect mBound;
private Paint mPaint;
/**
* 如果三个构造函数都是super,就是报错nullPointerException。
* 如果都是this,直接就编译过不了。
* 必须是前两个this,实现的super。
* this表示当前的view对象,也就是CustomViewNjj这个对象,this表示调用它的构造方法,一个参数调两个参数,
* 两个参数调三个参数,直到实现的地方调用super,重新父类view的方法。
* 如果三个都是this,那么就没有重写父类的方法,直接报错。
* 如果三个都写super,那么调用一个参数的构造参数的时候,就已经重写了父类view的方法,可是却没有具体的实现,
* 此时就会报空指针的错误。
* (以上是我的个人总结)
* 不过好像三个构造函数都是super,只要每个构造函数中都有实现的方法,不至于是没有初始化,导致空指针就好。
*/
/**
* public View (Context context)是在java代码创建视图的时候被调用,如果是从xml填充的视图,就不会调用这个
* public View (Context context, AttributeSet attrs)这个是在xml创建但是没有指定style的时候被调用
* public View (Context context, AttributeSet attrs, int defStyle)是指定style之后调用的
*/
/**
* 其实,从源码来看,两个参数的构造函数中,没有做任何处理,只是调用了this(context, attrs, 0);
* 三个参数的构造函数中,第一句话就是 this(context);然后后面有做了一堆处理。
* 然后在一个参数的构造函数中,将context传递给了全局使用的mContext,用于全局使用
*
* @param context
*/
public CustomViewNjj(Context context) {
this(context, null);
Log.i(TAG, "one params");
}
public CustomViewNjj(Context context, AttributeSet attrs) {
this(context, attrs, 0);
Log.i(TAG, "two params");
// TypedArray ta1 = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
}
/**
* 在有三个参数的构造函数中才能执行下列操作
*/
public CustomViewNjj(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
Log.i(TAG, "threee params");
TypedArray ta = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.CustomView, defStyleAttr, 0);
int n = ta.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = ta.getIndex(i);
switch (attr) {
case R.styleable.CustomView_titleText:
mTitleText = ta.getString(attr);
break;
case R.styleable.CustomView_titleTextColor1:
mTitleTextColor = ta.getColor(attr, Color.BLACK);
break;
case R.styleable.CustomView_titleTextSize:
mTitleTextSize = ta.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
break;
}
}
/**
* 下面的for循环只是为了打印参数信息,不做任何实际用处
* 获得的是CustomViewNjj所有属性,包括自定义和非自定义的。
* 比如:njjcustom:titleText="@string/hello_world"
* 获得的结果就是:attrName = titleText , attrVal = @2131099670
* 通过AttributeSet获得是id,如果引用了更深一层,就无法直接解析了。
* 所以这时就要用TypedArray,它简化了这个过程。
*/
int count = attrs.getAttributeCount();
for (int i = 0; i < count; i++) {
String attrName = attrs.getAttributeName(i);
String attrVal = attrs.getAttributeValue(i);
//Log.i("NieJianJian", "attrName = " + attrName + " , attrVal = " + attrVal);
}
ta.recycle();
mPaint = new Paint();
mPaint.setTextSize(mTitleTextSize);
mBound = new Rect();
mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);
this.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
mTitleText = randomText();
postInvalidate();
}
});
}
private String randomText() {
Random random = new Random();
Set<Integer> set = new HashSet<Integer>();
while (set.size() < 4) {
int randomInt = random.nextInt(10);
set.add(randomInt);
}
StringBuilder builder = new StringBuilder();
for (Integer i : set) {
builder.append("" + i);
}
return builder.toString();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 测量大小的方法
Log.i(TAG, "onMeasure");
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
/*
* EXACYTLY 一般是设置了明确的值或者是MATH_PARENT
* AT_MOST 表示子布局限制在一个最大值内,一般为WARP_PARENT
* UNSPECIFIED 表示子布局想要多大就多大,很少使用
*/
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else {
width = getPaddingLeft() + getPaddingRight() + mBound.width();
}
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
height = getPaddingTop() + getPaddingBottom() + mBound.height();
}
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) { // 绘制的方法
Log.i(TAG, "onDraw");
super.onDraw(canvas);
mPaint.setColor(Color.YELLOW);
// 绘制一个矩形
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
mPaint.setColor(mTitleTextColor); // 字体颜色
canvas.drawText(mTitleText, getWidth() / 2 - mBound.width() / 2,
getHeight() / 2 + mBound.height() / 2, mPaint);
}
}
/**
* 绘制VIew本身的内容,通过调用View.onDraw(canvas)函数实现
* 绘制自己的孩子通过dispatchDraw(canvas)实现
*/
/**
* View组件的绘制会调用draw(Canvas canvas)方法,draw过程中主要是先画Drawable背景,
* 对 drawable调用setBounds()然后是draw(Canvas c)方法.
* 有点注意的是背景drawable的实际大小会影响view组件的大小,
* drawable的实际大小通过getIntrinsicWidth()和getIntrinsicHeight()获取,
* 当背景比较大时view组件大小等于背景drawable的大小。
* 画完背景后,draw过程会调用onDraw(Canvas canvas)方法,
* 然后就是dispatchDraw(Canvas canvas)方法, dispatchDraw()主要是分发给子组件进行绘制,
* 我们通常定制组件的时候重写的是onDraw()方法。值得注意的是ViewGroup容器组件的绘制,
* 当它没有背景时直接调用的是dispatchDraw()方法, 而绕过了draw()方法,当它有背景的时候就调用draw()方法,
* 而draw()方法里包含了dispatchDraw()方法的调用。
* 因此要在ViewGroup上绘制东西的时候往往重写的是dispatchDraw()方法而不是onDraw()方法,
* 或者自定制一个Drawable,重写它的draw(Canvas c)和 getIntrinsicWidth(),getIntrinsicHeight()方法,
* 然后设为背景。
*/
/**
* 执行顺序是这样onMeasure -> onLayout -> onMeasure -> onLayout -> draw -> onDraw -> dispatchDraw
*/
6.RxJava的使用
RxJava,RxAndroid,顺便使用Java 8的Lambda表达式。使用的开发工具是Android Studio。
针对上面,BDAuction是一个Project,也就是一个项目,对应的app是一个module,一个project中可以有多个module。
每一个module中都有一个build.gradle,整个project只有一个build.gradle。
1).配置RxJava和RxAndroid
我们要使用,首先添加依赖,
在app module节点下的build.gradle文件中,dependencies中添加以下内容,
<pre style="font-family: Consolas; font-size: 12pt; background-color: rgb(199, 237, 204);">compile <span style="color:#008000;"><strong>'io.reactivex:rxandroid:1.0.1'
</strong></span>compile <span style="color:#008000;"><strong>'io.reactivex:rxjava:1.0.14'</strong></span>
然后Sync Now将gradle同步一下就可以了。
也可以在File -> Project Structure ->
选择app,Dependencies,加号,选择Library Dependency,然后在搜索框中输入
io.reactivex:rxandroid:1.0.1
找到后点击Ok就可以了。rxandroid添加完了,rxjava同理。
关于rx的就添加完了
2).lambda配置
lambda是java8的新特性,首先,得保证java版本,之后在配置。
第一步:在Project节点下的build.gradle中的dependencies中添加
classpath 'me.tatarka:gradle-retrolambda:3.2.4'
第二步:在app Module节点下的build.gradle中根节点中添加
apply plugin: 'me.tatarka.retrolambda'
第二步必须在第一步前面,顺序不能点到,否则报错
第三步:在app Module节点下的build.gradle文件的androdi结点下,添加如下内容
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
到此为止,lambda就配置完了
7.播放Gif图
GitHub框架地址:https://github.com/felipecsl/GifImageView
首先需要添加依赖
compile 'com.felipecsl:gifimageview:2.0.0'
布局文件:
<?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"
android:orientation="vertical">
<com.felipecsl.gifimageview.library.GifImageView
android:id="@+id/gifImageView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Activity
package com.example.administrator.rx_test;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.Button;
import android.widget.Toast;
import com.felipecsl.gifimageview.library.GifImageView;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
/**
* Created by Administrator on 2016/3/30.
*/
public class ThirdActivity extends Activity {
public GifImageView gifView;
public InputStream is = null;
public byte[] buffer = null;
static MyHandler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
gifView = (GifImageView) findViewById(R.id.gifImageView);
handler = new MyHandler(this);
handler.sendEmptyMessage(0);
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
gifView.stopAnimation();
}
class MyHandler extends Handler {
Context mContext;
public MyHandler(Context context) {
this.mContext = context;
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
try {
is = getAssets().open("intro.gif");
int size = is.available();
buffer = new byte[size];
is.read(buffer);
is.close();
gifView.setBytes(buffer);
gifView.startAnimation();
} catch (Exception e) {
}
}
}
}
就是这么简单,项目框架的部分是从网上加载的gif图,如果放在本地的话,就用流读取成bytes,然后传递给getBytes就可以了。
8.AnimatorSet和ObjectAnimator制作引导界面动画
下载地址:http://download.csdn.net/detail/u012975370/9482290
这两张gif图动画只播放一次,速度比较快,要快速查看才行。这只是其中的一两个界面。
其中的远点是一直动的,周围放大,透明度降低,一直循环,提示点击。
其实可以查看ObjectAnimator和AnimatorSet的原码,就知道有那些方法了,字面意思就可以看个大概,然后尝试下,就能知道效果是什么了。
布局文件Activity_splash.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">
<Button
android:id="@+id/introBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:text="introPage" />
<ViewStub
android:id="@+id/intro_vs"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout="@layout/layout_intro" />
</RelativeLayout>
SplashActivity.java
package com.example.administrator.rx_test;
import android.app.Activity;
import android.os.Bundle;
import android.view.ViewStub;
import android.view.animation.AnimationSet;
import android.widget.Button;
/**
* Created by Administrator on 2016/3/31.
*/
public class SplashActivity extends Activity {
private Button introBtn;
private ViewStub intro_vs;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
intro_vs = (ViewStub) findViewById(R.id.intro_vs);
introBtn = (Button) findViewById(R.id.introBtn);
introBtn.setOnClickListener(v -> showIntro());
}
private void showIntro() {
UserInfoView userInfoView = (UserInfoView) intro_vs.inflate();
}
}
UserInfoView.java
package com.example.administrator.rx_test;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AnimationSet;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.Toast;
/**
* Created by Administrator on 2016/3/31.
*/
public class UserInfoView extends FrameLayout {
View intro0;
View intro1;
View intro2;
View intro3;
View intro4;
View intro5;
View intro6;
View intro7;
AnimatorSet set = new AnimatorSet();
public UserInfoView(Context context) {
this(context, null);
}
public UserInfoView(Context context, AttributeSet attrs) {
// 必须是this,不能是super
this(context, attrs, 0);
// super(context, attrs, 0);
}
public UserInfoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
inflate(context, R.layout.intro_view_detail, this);
initView();
intBtn();
}
private void initView() {
intro0 = findViewById(R.id.view_intro_0);
intro1 = findViewById(R.id.view_intro_1);
intro2 = findViewById(R.id.view_intro_2);
intro3 = findViewById(R.id.view_intro_3);
intro4 = findViewById(R.id.view_intro_4);
intro5 = findViewById(R.id.view_intro_5);
intro6 = findViewById(R.id.view_intro_6);
intro7 = findViewById(R.id.view_intro_7);
((Button) findViewById(R.id.intro7_btn)).setOnClickListener(v -> Toast.makeText(getContext(), "aa", Toast.LENGTH_LONG).show());
}
private void intBtn() {
initClick(R.id.intro0_btn, intro1);
initClick(R.id.intro1_btn, intro2);
initClick(R.id.intro2_btn, intro3);
initClick(R.id.intro3_btn, intro4);
initClick(R.id.intro4_btn, intro5);
initClick(R.id.intro5_btn, intro6);
initClick(R.id.intro6_btn, intro7);
}
private void initClick(int id, View view) {
((Button) findViewById(id)).setOnClickListener(v -> {
view.bringToFront();
// if (set.isRunning()) {
// set.end();
// }
startAnime(view);
});
}
private void startAnime(View view) {
int id = view.getId();
switch (id) {
case R.id.view_intro_1:
intro1Anime();
break;
case R.id.view_intro_2:
intro2Anime();
break;
case R.id.view_intro_3:
intro3Anime();
break;
case R.id.view_intro_4:
intro4Anime();
break;
case R.id.view_intro_5:
intro5Anime();
break;
case R.id.view_intro_6:
intro6Anime();
break;
case R.id.view_intro_7:
intro7Anime();
break;
}
}
private void startPointAnime(View vBtn, long delay) {
// 透明动画
ObjectAnimator alpha = ObjectAnimator.ofFloat(vBtn, "alpha",
1.0f, 0.8f, 0.6f, 0.4f, 0.2f, 0.0f);
alpha.setRepeatCount(ValueAnimator.INFINITE);
alpha.setRepeatMode(ValueAnimator.RESTART);
// 缩放动画
ObjectAnimator scaleX = ObjectAnimator.ofFloat(vBtn, "scaleX", 1.0f, 1.2f, 1.4f, 1.5f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(vBtn, "scaleY", 1.0f, 1.2f, 1.4f, 1.5f);
scaleX.setRepeatCount(ValueAnimator.INFINITE);
scaleX.setRepeatMode(ValueAnimator.RESTART);
scaleY.setRepeatCount(ValueAnimator.INFINITE);
scaleY.setRepeatMode(ValueAnimator.RESTART);
set.setDuration(1000);
set.playTogether(alpha, scaleX, scaleY);
set.setStartDelay(delay);
set.start();
}
private void startViewAnime(View view, long delay, float... values) {
ObjectAnimator anime = ObjectAnimator.ofFloat(view, "alpha", values).setDuration(300);
anime.setStartDelay(delay);
anime.start();
}
private void intro1Anime() {
ImageView intro_1_1 = (ImageView) findViewById(R.id.intro_1_1);
ImageView intro_1_2 = (ImageView) findViewById(R.id.intro_1_2);
ImageView intro_1_3 = (ImageView) findViewById(R.id.intro_1_3);
ImageView intro_1_black = (ImageView) findViewById(R.id.intro_1_black);
Button intro1_btn = (Button) findViewById(R.id.intro1_btn);
startViewAnime(intro_1_black, 200, 0, 1);
startViewAnime(intro_1_2, 300, 0, 1);
startViewAnime(intro_1_3, 500, 0, 1);
startViewAnime(intro1_btn, 800, 0, 1);
startViewAnime(findViewById(R.id.intro1_btn_f), 800, 0, 1);
startPointAnime(intro1_btn, 1500);
}
private void intro2Anime() {
ImageView intro_2_2 = (ImageView) findViewById(R.id.intro_2_2);
ImageView intro_2_3 = (ImageView) findViewById(R.id.intro_2_3);
ImageView intro_2_4 = (ImageView) findViewById(R.id.intro_2_4);
ImageView intro_2_5 = (ImageView) findViewById(R.id.intro_2_5);
ImageView intro_2_black = (ImageView) findViewById(R.id.intro_2_black);
Button intro2_btn = (Button) findViewById(R.id.intro2_btn);
startViewAnime(intro_2_black, 200, 0, 1);
startViewAnime(intro_2_2, 300, 0, 1);
startViewAnime(intro_2_3, 400, 0, 1);
startViewAnime(intro_2_2, 2000, 1, 0);
startViewAnime(intro_2_3, 2000, 1, 0);
startViewAnime(intro_2_4, 2200, 0, 1);
startViewAnime(intro_2_5, 2500, 0, 1);
startViewAnime(intro2_btn, 2500, 0, 1);
startViewAnime(findViewById(R.id.intro2_btn_f), 2200, 0, 1);
startPointAnime(intro2_btn, 2800);
}
private void intro3Anime() {
ImageView intro_3_2 = (ImageView) findViewById(R.id.intro_3_2);
ImageView intro_3_3 = (ImageView) findViewById(R.id.intro_3_3);
ImageView intro_3_4 = (ImageView) findViewById(R.id.intro_3_4);
Button intro3_btn = (Button) findViewById(R.id.intro3_btn);
ObjectAnimator anime1 = ObjectAnimator.ofFloat(intro_3_3, "translationY", -intro_3_2.getHeight())
.setDuration(300);
anime1.setStartDelay(100);
anime1.start();
startViewAnime(intro_3_4, 200, 0, 1);
startViewAnime(intro3_btn, 500, 0, 1);
startViewAnime(findViewById(R.id.intro3_btn_f), 500, 0, 1);
startPointAnime(intro3_btn, 800);
}
private void intro4Anime() {
ImageView intro_4_2 = (ImageView) findViewById(R.id.intro_4_2);
ImageView intro_4_3 = (ImageView) findViewById(R.id.intro_4_3);
ImageView intro_4_4 = (ImageView) findViewById(R.id.intro_4_4);
ImageView intro_4_5 = (ImageView) findViewById(R.id.intro_4_5);
ImageView intro_4_black = (ImageView) findViewById(R.id.intro_4_black);
Button intro4_btn = (Button) findViewById(R.id.intro4_btn);
startViewAnime(intro_4_black, 200, 0, 1);
startViewAnime(intro_4_2, 300, 0, 1);
startViewAnime(intro_4_3, 400, 0, 1);
startViewAnime(intro_4_2, 2000, 1, 0);
startViewAnime(intro_4_3, 2000, 1, 0);
startViewAnime(intro_4_4, 2200, 0, 1);
startViewAnime(intro_4_5, 2200, 0, 1);
startViewAnime(intro4_btn, 2500, 0, 1);
startViewAnime(findViewById(R.id.intro4_btn_f), 2500, 0, 1);
startPointAnime(intro4_btn, 2800);
}
private void intro5Anime() {
ImageView intro_5_2 = (ImageView) findViewById(R.id.intro_5_2);
ImageView intro_5_3 = (ImageView) findViewById(R.id.intro_5_3);
ImageView intro_5_black = (ImageView) findViewById(R.id.intro_5_black);
Button intro5_btn = (Button) findViewById(R.id.intro5_btn);
startViewAnime(intro_5_black, 200, 0, 1);
startViewAnime(intro_5_2, 300, 0, 1);
startViewAnime(intro_5_3, 400, 0, 1);
startViewAnime(intro5_btn, 700, 0, 1);
startViewAnime(findViewById(R.id.intro5_btn_f), 700, 0, 1);
startPointAnime(intro5_btn, 1000);
}
private void intro6Anime() {
ImageView intro_6_2 = (ImageView) findViewById(R.id.intro_6_2);
ImageView intro_6_3 = (ImageView) findViewById(R.id.intro_6_3);
Button intro6_btn = (Button) findViewById(R.id.intro6_btn);
startViewAnime(intro_6_2, 200, 0, 1);
startViewAnime(intro_6_3, 300, 0, 1);
startViewAnime(intro6_btn, 600, 0, 1);
startViewAnime(findViewById(R.id.intro6_btn_f), 600, 0, 1);
startPointAnime(intro6_btn, 900);
}
private void intro7Anime() {
ImageView intro_7_2 = (ImageView) findViewById(R.id.intro_7_2);
ImageView intro_7_3 = (ImageView) findViewById(R.id.intro_7_3);
ImageView intro_7_4 = (ImageView) findViewById(R.id.intro_7_4);
Button intro7_btn = (Button) findViewById(R.id.intro7_btn);
ImageView intro_7_black = (ImageView) findViewById(R.id.intro_7_black);
startViewAnime(intro_7_black, 200, 0, 1);
startViewAnime(intro_7_2, 300, 0, 1);
startViewAnime(intro_7_3, 400, 0, 1);
startViewAnime(intro_7_2, 2000, 1, 0);
startViewAnime(intro_7_3, 2000, 1, 0);
startViewAnime(intro_7_4, 2300, 0, 1);
startViewAnime(intro7_btn, 2300, 0, 1);
}
}
intro_view_detail.xml文件
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/view_intro_7"
layout="@layout/view_intro_7"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include
android:id="@+id/view_intro_6"
layout="@layout/view_intro_6"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include
android:id="@+id/view_intro_5"
layout="@layout/view_intro_5"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include
android:id="@+id/view_intro_4"
layout="@layout/view_intro_4"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include
android:id="@+id/view_intro_3"
layout="@layout/view_intro_3"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include
android:id="@+id/view_intro_2"
layout="@layout/view_intro_2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include
android:id="@+id/view_intro_1"
layout="@layout/view_intro_1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<include
android:id="@+id/view_intro_0"
layout="@layout/view_intro_0"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</merge>
每一个界面的显示代码,就不贴了,有兴趣的可以去下载看看:
http://download.csdn.net/detail/u012975370/9482290
9.简单的回调
public class MainActivity extends Activity {
Button1 mButton1;
Button mButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButton1 = new Button1();
mButton1.setOnClickListener1(new OnClickListener1() {
@Override
public void onClick() {
Log.i("niejianjian"," -> 1");
Toast.makeText(getApplicationContext(), "click", Toast.LENGTH_LONG).show();
}
});
mButton = (Button) findViewById(R.id.showBtn);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("niejianjian"," -> 2");
mButton1.click();
}
});
}
}
interface OnClickListener1 {
public void onClick();
}
class Button1 {
OnClickListener1 mListener1;
public void click() {
Log.i("niejianjian"," -> 3");
mListener1.onClick();
}
public void setOnClickListener1(OnClickListener1 listener1) {
Log.i("niejianjian"," -> 4");
this.mListener1 = listener1;
}
}
10.简单的自定义进度条
效果图
CircleProgressView类
package com.example.jian.myapplication;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by jian on 2016/9/20.
*/
public class CircleProgressView extends View {
private int mMeasureHeight;
private int mMeasureWidth;
private Paint mCirclePaint;
private float mCircleXY;
private float mRadius;
private Paint mArcPaint;
private RectF mArcRectF;
private float mSweepAngle;
private float mSweepValue = 66;
private Paint mTextPaint;
private String mShowText;
private float mShowTextSize;
public CircleProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mMeasureWidth = MeasureSpec.getSize(widthMeasureSpec);
mMeasureHeight = MeasureSpec.getSize(heightMeasureSpec);
// 设定测量出的大小
setMeasuredDimension(mMeasureWidth, mMeasureHeight);
initViews();
}
private void initViews() {
float length = 0;
if (mMeasureWidth > mMeasureHeight) {
length = mMeasureHeight;
} else {
length = mMeasureWidth;
}
mCircleXY = length / 2;
mRadius = (float) (length * 0.5 / 2);
mCirclePaint = new Paint();
// 抗锯齿
mCirclePaint.setAntiAlias(true);
mCirclePaint.setColor(getResources().getColor(android.R.color.holo_blue_bright));
mArcRectF = new RectF(
(float) (length * 0.1),
(float) (length * 0.1),
(float) (length * 0.9),
(float) (length * 0.9)
);
// 获取绘画的角度值
mSweepAngle = (mSweepValue / 100f) * 360f;
mArcPaint = new Paint();
mArcPaint.setAntiAlias(true);
mArcPaint.setColor(getResources().getColor(android.R.color.holo_blue_bright));
// 实心宽度
mArcPaint.setStrokeWidth((float) (length * 0.1));
mArcPaint.setStyle(Paint.Style.STROKE);
mShowText = setShowText();
mShowTextSize = setShowTextSize();
mTextPaint = new Paint();
mTextPaint.setTextSize(mShowTextSize);
mTextPaint.setTextAlign(Paint.Align.CENTER);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制圆
canvas.drawCircle(mCircleXY, mCircleXY, mRadius, mCirclePaint);
// 绘制弧线(扇形)
canvas.drawArc(mArcRectF, 270, mSweepAngle, false, mArcPaint);
// 绘制文字
canvas.drawText(mShowText, 0, mShowText.length(), mCircleXY, mCircleXY + (mShowTextSize / 4), mTextPaint);
}
private float setShowTextSize() {
this.invalidate();
return 100;
}
private String setShowText() {
this.invalidate();
return "Android Skill";
}
public void setSweepValue(float sweepValue) {
if (sweepValue != 0) {
mSweepValue = sweepValue;
} else {
mSweepValue = 25;
}
this.invalidate();
}
}
activity_main.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">
<com.example.jian.myapplication.CircleProgressView
android:id="@+id/circle"
android:layout_width="match_parent"
android:layout_height="match_parent"/>/>
</RelativeLayout>
MainActivity
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CircleProgressView circleProgressView = (CircleProgressView) findViewById(R.id.circle);
circleProgressView.setSweepValue(66);
}
}
11.ListView的使用技巧
简单的listview以及常用到的相关方法
MainActivity
package com.example.jian.myapplication;
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import com.example.jian.myapplication.listview.ViewHolderApdater;
import java.util.ArrayList;
import java.util.List;
/**
* Created by jian on 2016/9/19.
*/
public class MainActivity extends Activity {
ListView mListView;
private List<String> data = new ArrayList<String>();
private ViewHolderApdater mAdapter;
private int lastVisibleImtePosition;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.listview);
getData();
mAdapter = new ViewHolderApdater(this, data);
mListView.setAdapter(mAdapter);
// 设置第一个选中的item,其实类似于scrollTo
// mListView.setSelection(0);
// 设置滚动条在左边
// mListView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_LEFT);
// 设置空view
// mListView.setEmptyView(new View(this)); // 传入一个view对象参数
mListView.setOnTouchListener(new MyOnTouchListener());
mListView.setOnItemClickListener(new MyOnItemClickListener());
mListView.setOnScrollListener(new MyOnScrollListener());
mListView.getFirstVisiblePosition();
mListView.getLastVisiblePosition();
}
/*遍历listView的的子view*/
public void getListViewItem() {
for (int i = 0; i < mListView.getChildCount(); i++) {
View view = mListView.getChildAt(i);
}
}
private List<String> getData() {
for (int i = 0; i < 20; i++) {
data.add("第 " + i + " 个");
}
return data;
}
class MyOnScrollListener implements AbsListView.OnScrollListener {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
// 滑动时停止
break;
case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
// 正在滚动
break;
case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
// 手指抛动时,即用手指滑动
// 在离开后ListView由于惯性继续滑动
break;
}
}
/**
* @param view
* @param firstVisibleItem // 当前显示的第一个item的position
* @param visibleItemCount // 当前屏幕总共显示的item的个数
* @param totalItemCount // listview的总数
*/
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// 滚动时一直调用
if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {
// 说明滚动到了最后一行
}
if (firstVisibleItem > lastVisibleImtePosition) {
// 上滑
} else if (firstVisibleItem < lastVisibleImtePosition) {
// 下滑
}
lastVisibleImtePosition = firstVisibleItem;
}
}
class MyOnItemClickListener implements AdapterView.OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(MainActivity.this, " " + position, Toast.LENGTH_SHORT).show();
if (position == 5) {
data.add("第 " + (data.size()) + " 个");
mAdapter.notifyDataSetChanged();
}
if (position == 6) {
data.remove(data.size() - 1);
mAdapter.notifyDataSetChanged();
}
if (position == 7) {
// 移动的距离,offset = 2,就是向下移动两个item的距离,如果offset = -2,那就是向上移动两个item的距离
// mListView.smoothScrollByOffset(-2);
// 移动到固定的位置,和setSelection一样
// mListView.smoothScrollToPosition(1);
// 双击 distance是移动的像素数,duration是动画时间
// mListView.smoothScrollBy(500, 1000);
}
}
}
class MyOnTouchListener implements View.OnTouchListener {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 触摸时操作
break;
case MotionEvent.ACTION_MOVE:
// 移动时操作
break;
case MotionEvent.ACTION_UP:
// 离开时操作
break;
}
return false;
}
}
}
ViewHolderAdapter
package com.example.jian.myapplication.listview;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.jian.myapplication.R;
import java.util.List;
/**
* Created by jian on 2016/9/21.
*/
public class ViewHolderApdater extends BaseAdapter {
private List<String> mData;
private LayoutInflater mLayoutInflater;
public ViewHolderApdater(Context context, List<String> data) {
this.mData = data;
mLayoutInflater = LayoutInflater.from(context);
// mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = mLayoutInflater.inflate(R.layout.list_item, null);
holder.img = (ImageView) convertView.findViewById(R.id.imageView);
holder.title = (TextView) convertView.findViewById(R.id.textView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.img.setBackgroundResource(R.drawable.ic_launcher);
holder.title.setText(mData.get(position));
return convertView;
}
public final class ViewHolder {
public ImageView img;
public TextView title;
}
}
activity_main.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">
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:dividerHeight="10dp"
android:paddingLeft="20dp"/>
<!--android:divider="@null"--> <!--设置无滚动条-->
<!--android:divider="@android:color/darker_gray"--> <!--设置滚动条颜色-->
<!--android:listSelector="#00000000"
android:listSelector="@android:color/transparent"--> <!--取消点击效果-->
</RelativeLayout>
list_item.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">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="20dp"
android:layout_toRightOf="@+id/imageView"/>
</RelativeLayout>
具有弹性的ListView
CustomListView
package com.example.jian.myapplication.listview;
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.widget.ListView;
/**
* Created by jian on 2016/9/22.
*/
public class CustomListView extends ListView {
Context mContext;
private static int mMaxOverDistance = 50;
public CustomListView(Context context) {
super(context);
this.mContext = context;
initView();
}
public CustomListView(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
initView();
}
public CustomListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.mContext = context;
initView();
}
private void initView() {
DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
float density = metrics.density;
mMaxOverDistance = (int) (density * mMaxOverDistance);
}
@Override
protected boolean overScrollBy(int deltaX, int deltaY,
int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY,
boolean isTouchEvent) {
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY,
scrollRangeX, scrollRangeY, maxOverScrollX,
mMaxOverDistance, isTouchEvent);
}
}
MainActivity
package com.example.jian.myapplication;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import com.example.jian.myapplication.listview.CustomListView;
/**
* Created by jian on 2016/9/22.
*/
public class MainActivity extends Activity {
CustomListView mCustomListView;
private String[] data = new String[30];
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCustomListView = (CustomListView) findViewById(R.id.listview);
for (int i = 0; i < 30; i++) {
data[i] = "" + i;
}
mCustomListView.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, data));
}
}
带显示隐藏ToolBar的ListView
ScrollHideListView
package com.example.jian.myapplication.listview;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import com.example.jian.myapplication.R;
/**
* Created by jian on 2016/9/22.
*/
public class ScrollHideListView extends Activity {
private Toolbar mToolbar;
private ListView mListView;
private String[] mStr = new String[20];
private int mTouchSlop;
private float mFirstY;
private float mCurrentY;
private int direction;
private ObjectAnimator mAnimator;
private boolean mShow = true;
View.OnTouchListener myTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mFirstY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
mCurrentY = event.getY();
if (mCurrentY - mFirstY > mTouchSlop) {
direction = 0;// down
} else if (mFirstY - mCurrentY > mTouchSlop) {
direction = 1;// up
}
if (direction == 1) {
if (mShow) {
toolbarAnim(1);//show
mShow = !mShow;
}
} else if (direction == 0) {
if (!mShow) {
toolbarAnim(0);//hide
mShow = !mShow;
}
}
break;
case MotionEvent.ACTION_UP:
break;
}
return false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.scroll_hide);
// 系统认为的最低滑动距离
mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
mToolbar = (Toolbar) findViewById(R.id.toolbar);
mListView = (ListView) findViewById(R.id.listview);
for (int i = 0; i < mStr.length; i++) {
mStr[i] = "Item " + i;
}
View header = new View(this);
header.setLayoutParams(new AbsListView.LayoutParams(
AbsListView.LayoutParams.MATCH_PARENT,
(int) getResources().getDimension(
R.dimen.abc_action_bar_default_height_material)));
// 防止toolbar挡住listview,给listview添加一个header
mListView.addHeaderView(header);
mListView.setAdapter(new ArrayAdapter<String>(
ScrollHideListView.this,
android.R.layout.simple_expandable_list_item_1,
mStr));
mListView.setOnTouchListener(myTouchListener);
}
private void toolbarAnim(int flag) {
if (mAnimator != null && mAnimator.isRunning()) {
mAnimator.cancel();
}
if (flag == 0) {
mAnimator = ObjectAnimator.ofFloat(mToolbar,
"translationY", mToolbar.getTranslationY(), 0);
} else {
mAnimator = ObjectAnimator.ofFloat(mToolbar,
"translationY", mToolbar.getTranslationY(),
-mToolbar.getHeight());
}
mAnimator.start();
}
}
scroll_hdie.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"
tools:context=".listview.ScrollHideListView">
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:headerDividersEnabled="false"/>
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@android:color/holo_blue_light"/>
</RelativeLayout>
聊天ListView
两种布局,聊天单条内容背景采用的是.9图片,因为拉伸不失真。
chat_item_itemout.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="match_parent"
android:gravity="center_vertical|right"
android:orientation="horizontal"
android:padding="10dp">
<TextView
android:id="@+id/text_out"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/chatitem_out_bg"
android:gravity="center"
android:textSize="20sp" />
<ImageView
android:id="@+id/icon_out"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />
</LinearLayout>
chat_item_itemin.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="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="10dp">
<ImageView
android:id="@+id/icon_in"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/text_in"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/chatitem_in_bg"
android:gravity="center"
android:textSize="20sp" />
</LinearLayout>
ChatItemAdapter.java
package com.example.jian.myapplication.listview;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.jian.myapplication.R;
import java.util.List;
/**
* Created by jian on 2016/9/23.
*/
public class ChatItemAdapter extends BaseAdapter {
private List<ChatItemBean> mData;
private LayoutInflater mInflater;
Context mContext;
public ChatItemAdapter(Context context, List<ChatItemBean> data) {
this.mData = data;
this.mContext = context;
mInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return mData.size();
}
@Override
public Object getItem(int position) {
return mData.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
/**
* 返回第position个item是何种类型
*/
@Override
public int getItemViewType(int position) {
ChatItemBean bean = mData.get(position);
return bean.getType();
}
/**
* 返回不同布局的总数,就是有几种布局
*/
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
if (getItemViewType(position) == 0) {
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.chat_item_itemin, null);
holder.text = (TextView) convertView.findViewById(R.id.text_in);
holder.icon = (ImageView) convertView.findViewById(R.id.icon_in);
} else {
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.chat_item_itemout, null);
holder.text = (TextView) convertView.findViewById(R.id.text_out);
holder.icon = (ImageView) convertView.findViewById(R.id.icon_out);
}
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.icon.setImageBitmap(BitmapFactory.decodeResource(
mContext.getResources(), (getItemViewType(position) == 0) ?
R.drawable.in_icon : R.drawable.ic_launcher));
holder.text.setText(mData.get(position).getText());
return convertView;
}
public final class ViewHolder {
public TextView text;
public ImageView icon;
}
}
ChatItemBean.java
package com.example.jian.myapplication.listview;
import android.graphics.Bitmap;
/**
* Created by jian on 2016/9/23.
*/
public class ChatItemBean {
private int type;
private String text;
private Bitmap icon;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Bitmap getIcon() {
return icon;
}
public void setIcon(Bitmap icon) {
this.icon = icon;
}
}
MainActivity.java
package com.example.jian.myapplication;
import android.app.Activity;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ListView;
import com.example.jian.myapplication.listview.ChatItemAdapter;
import com.example.jian.myapplication.listview.ChatItemBean;
import java.util.ArrayList;
import java.util.List;
/**
* Created by jian on 2016/9/22.
*/
public class MainActivity extends Activity {
private ListView mListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.listview);
mListView.setAdapter(new ChatItemAdapter(this, getData()));
}
private List<ChatItemBean> getData() {
ChatItemBean bean1 = new ChatItemBean();
bean1.setType(0);
bean1.setText("Hello, How are you?");
bean1.setIcon(BitmapFactory.decodeResource(getResources(), R.drawable.in_icon));
ChatItemBean bean2 = new ChatItemBean();
bean2.setType(0);
bean2.setText("Fine thank you,and you?");
bean2.setIcon(BitmapFactory.decodeResource(getResources(), R.drawable.in_icon));
ChatItemBean bean3 = new ChatItemBean();
bean3.setType(1);
bean3.setText("I'm fine too");
bean3.setIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher));
ChatItemBean bean4 = new ChatItemBean();
bean4.setType(0);
bean4.setText("bye");
bean4.setIcon(BitmapFactory.decodeResource(getResources(), R.drawable.in_icon));
ChatItemBean bean5 = new ChatItemBean();
bean5.setType(1);
bean5.setText("now,I will go back");
bean5.setIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher));
ChatItemBean bean6 = new ChatItemBean();
bean6.setType(1);
bean6.setText("ok, bye");
bean6.setIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher));
ChatItemBean bean7 = new ChatItemBean();
bean7.setType(0);
bean7.setText("bye bye");
bean7.setIcon(BitmapFactory.decodeResource(getResources(), R.drawable.in_icon));
List<ChatItemBean> data = new ArrayList<>();
data.add(bean1);
data.add(bean2);
data.add(bean3);
data.add(bean4);
data.add(bean5);
data.add(bean6);
data.add(bean7);
return data;
}
}
activity_main.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="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@null"
android:listSelector="@android:color/transparent"/>
</LinearLayout>
12.自定义属性的复合控件
自定义属性attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TopBar">
<attr name="title" format="string"/>
<attr name="titleTextSize" format="dimension"/>
<attr name="titleTextColor" format="color"/>
<attr name="leftTextColor" format="color"/>
<attr name="leftBackground" format="reference|color"/>
<attr name="leftText" format="string"/>
<attr name="rightTextColor" format="color"/>
<attr name="rightBackground" format="reference|color"/>
<attr name="rightText" format="string"/>
</declare-styleable>
</resources>
自定义View:TopBar.java
package com.example.jian.myapplication.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.example.jian.myapplication.R;
/**
* Created by jian on 2016/10/12.
*/
public class TopBar extends RelativeLayout {
private Button mLeftBtn, mRightBtn;
private TextView mTitleTv;
// 左按钮的属性值
private int mLeftTextColor;
private Drawable mLeftBackground;
private String mLeftText;
// 右按钮的属性值
private int mRightTextColor;
private Drawable mRightBackground;
private String mRightText;
// 标题的属性值
private int mTitleTextColor;
private float mTitleTextSize;
private String mTitleText;
// 布局属性,用来控制组件元素在ViewGroup中的位置
private LayoutParams mLeftParams, mTitlepParams, mRightParams;
// 映射传入的接口对象
private TopBarClickListener mListener;
public TopBar(Context context) {
super(context);
}
public TopBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public TopBar(Context context, AttributeSet attrs) {
super(context, attrs);
// 通过这个方法,将你在attrs.xml中定义的declare-styleable的所以属性的值存储到TypedArray中
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar);
getAttrs(ta);
setAttrs(context);
setLayout();
setBtnClickListener();
}
/**
* 从TypedArray中取出对应的值,为要设置的属性赋值
*/
private void getAttrs(TypedArray ta) {
mLeftTextColor = ta.getColor(R.styleable.TopBar_leftTextColor, 0);
mLeftBackground = ta.getDrawable(R.styleable.TopBar_leftBackground);
mLeftText = ta.getString(R.styleable.TopBar_leftText);
mRightTextColor = ta.getColor(R.styleable.TopBar_rightTextColor, 0);
mRightBackground = ta.getDrawable(R.styleable.TopBar_rightBackground);
mRightText = ta.getString(R.styleable.TopBar_rightText);
mTitleTextColor = ta.getColor(R.styleable.TopBar_titleTextColor, 0);
mTitleTextSize = ta.getDimension(R.styleable.TopBar_titleTextSize, 10);
mTitleText = ta.getString(R.styleable.TopBar_title);
// 获取完TypedArray的值后,一般要调用recyle方法来避免重新创建的时候的错误(资源回收)
ta.recycle();
}
/**
* 为创建的组件元素赋值
*/
private void setAttrs(Context context) {
mLeftBtn = new Button(context);
mRightBtn = new Button(context);
mTitleTv = new TextView(context);
mLeftBtn.setText(mLeftText);
mLeftBtn.setBackground(mLeftBackground);
mLeftBtn.setTextColor(mLeftTextColor);
mRightBtn.setText(mRightText);
mRightBtn.setBackground(mRightBackground);
mRightBtn.setTextColor(mRightTextColor);
mTitleTv.setText(mTitleText);
mTitleTv.setTextSize(mTitleTextSize);
mTitleTv.setTextColor(mTitleTextColor);
}
/**
* 为组件元素设置相应的布局元素
*/
private void setLayout() {
mLeftParams = new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT);
mLeftParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);
// 添加到ViewGroup
addView(mLeftBtn, mLeftParams);
mRightParams = new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT);
mRightParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, TRUE);
// 添加到ViewGroup
addView(mRightBtn, mRightParams);
mTitlepParams = new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT);
mTitlepParams.addRule(RelativeLayout.CENTER_IN_PARENT, TRUE);
addView(mTitleTv, mTitlepParams);
}
/**
* 按钮的点击实现,不需要具体的实现,
* 只需要嗲用接口的方法,回调的时候,会有具体的实现
*/
private void setBtnClickListener() {
mRightBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mListener.rightClick();
}
});
mLeftBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mListener.leftClick();
}
});
}
/**
* 设置按钮的显示与否 通过id区分按钮,flag区分是否显示
*
* @param id id
* @param flag 是否显示
*/
public void setButtonVisable(int id, boolean flag) {
if (flag) {
if (id == 0) {
mLeftBtn.setVisibility(View.VISIBLE);
} else {
mRightBtn.setVisibility(View.VISIBLE);
}
} else {
if (id == 0) {
mLeftBtn.setVisibility(View.GONE);
} else {
mRightBtn.setVisibility(View.GONE);
}
}
}
/**
* 接口对象,实现回调机制,在回调方法中,通过映射的接口对象调用接口中的方法,
* 而不用去考虑如何实现,具体的实现由调用者去创建
*/
public interface TopBarClickListener {
void leftClick();
void rightClick();
}
/**
* 暴露一个方法给调用者来注册接口回调,通过接口来获得回调这对接口方法的实现
*
* @param listener
*/
public void setOnTopBarClickListener(TopBarClickListener listener) {
this.mListener = listener;
}
}
MainActivity.java
package com.example.jian.myapplication;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;
import com.example.jian.myapplication.view.TopBar;
/**
* Created by jian on 2016/9/26.
*/
public class MainActivity extends Activity {
TopBar mTopBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_topbar);
mTopBar = (TopBar) findViewById(R.id.topbar);
mTopBar.setOnTopBarClickListener(new TopBar.TopBarClickListener() {
@Override
public void leftClick() {
Toast.makeText(MainActivity.this, "left", Toast.LENGTH_SHORT).show();
}
@Override
public void rightClick() {
Toast.makeText(MainActivity.this, "right", Toast.LENGTH_SHORT).show();
}
});
mTopBar.setButtonVisable(0,true);
mTopBar.setButtonVisable(1,true);
}
}
activity_topbar.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:topbar="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp">
<com.example.jian.myapplication.view.TopBar
android:id="@+id/topbar"
android:layout_width="match_parent"
android:layout_height="40dp"
topbar:leftBackground="@drawable/blue_button"
topbar:leftText="Back"
topbar:leftTextColor="#FFFFFF"
topbar:rightBackground="@drawable/blue_button"
topbar:rightText="More"
topbar:rightTextColor="#FFFFFF"
topbar:title="自定义标题"
topbar:titleTextColor="#123412"
topbar:titleTextSize="10sp"/>
</RelativeLayout>
blue_button.xml
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<!-- 填充的颜色 -->
<solid android:color="#33444444" />
</shape>
</item>
<item>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<!-- 填充的颜色 -->
<solid android:color="#3EC5FF" />
</shape>
</item>
</selector>
13.TextSwitcher实现上下滚动广告效果
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">
<TextSwitcher
android:id="@+id/textSwitcher"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="50dp"
android:background="#e4e4e4"
android:inAnimation="@anim/push_up_in"
android:minHeight="48dp"
android:outAnimation="@anim/push_up_out"/>
</RelativeLayout>
MainActivity.java
package com.example.jian.myapplication;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextSwitcher;
import android.widget.TextView;
import android.widget.ViewSwitcher;
/**
* Created by jian on 2016/9/26.
*/
public class MainActivity extends Activity {
private TextSwitcher mTextSwitcher;
private BitHandler bitHandler;
private String[] strings = {"text00001", "text00002"};
private int index = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_textswitcher);
mTextSwitcher = (TextSwitcher) findViewById(R.id.textSwitcher);
mTextSwitcher.setFactory(new ViewSwitcher.ViewFactory() {
@Override
public View makeView() {
TextView textView = new TextView(MainActivity.this);
textView.setSingleLine();
textView.setTextSize(15);
textView.setTextColor(Color.parseColor("#ff0000"));
textView.setEllipsize(TextUtils.TruncateAt.END);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT
);
lp.gravity = Gravity.CENTER;
textView.setLayoutParams(lp);
return textView;
}
});
bitHandler = new BitHandler();
bitHandler.sendEmptyMessage(0);
// new myThread().start();
}
class BitHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mTextSwitcher.setText(strings[index]);
index++;
if (index == strings.length) {
index = 0;
}
bitHandler.sendEmptyMessageDelayed(0, 2000);
}
}
private class myThread extends Thread {
@Override
public void run() {
super.run();
while (index < strings.length) {
try {
synchronized (this) {
bitHandler.sendEmptyMessage(0);
this.sleep(2000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
push_up_in.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false"
android:zAdjustment="top">
<translate
android:duration="400"
android:fromYDelta="100%"
android:toYDelta="0"/>
<alpha
android:duration="400"
android:fromAlpha="0.0"
android:toAlpha="1.0"/>
</set>
push_up_out.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false"
android:zAdjustment="top">
<translate
android:duration="400"
android:fromYDelta="0"
android:toYDelta="-100%"/>
<alpha
android:duration="400"
android:fromAlpha="1.0"
android:toAlpha="0.0"/>
</set>
14.工厂模式模版
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AudiFactory factory = new AudiCarFactory();
AudiCar q5car = factory.createAudiCar(AudiQ5.class);
q5car.drive();
q5car.selfNavigation();
AudiQ7 q7car = factory.createAudiCar(AudiQ7.class);
q7car.drive();
q7car.selfNavigation();
}
}
public abstract class AudiFactory {
public abstract <T extends AudiCar> T createAudiCar(Class<T> clz);
}
public class AudiCarFactory extends AudiFactory {
@Override
public <T extends AudiCar> T createAudiCar(Class<T> clz) {
AudiCar car = null;
try {
car = (AudiCar) Class.forName(clz.getName()).newInstance();
// car = (AudiCar) clz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T) car;
}
}
public abstract class AudiCar {
public abstract void drive();
public abstract void selfNavigation();
}
public class AudiQ5 extends AudiCar {
@Override
public void drive() {
Log.i("niejianjian", " -> AudiQ5 -> drive");
}
@Override
public void selfNavigation() {
Log.i("niejianjian", " -> AudiQ5 -> selfNavigation");
}
}
public class AudiQ7 extends AudiCar {
@Override
public void drive() {
Log.i("niejianjian", " -> AudiQ7 -> drive");
}
@Override
public void selfNavigation() {
Log.i("niejianjian", " -> AudiQ7 -> selfNavigation");
}
}
15.小圆点ViewPager指示器
/**
* 小圆点 ViewPager 指示器
* Created by WangWei on 2015/10/14.
*/
public class CircleViewPagerIndicator extends LinearLayout implements ViewPager.OnPageChangeListener {
protected static final int NORMAL_INDICATOR = R.drawable.indicator_slide_show;
protected static final int HIGHLIGHT_INDICATOR = R.drawable.indicator_slideshow_checked;
protected ViewPager mViewPager;
public CircleViewPagerIndicator(Context context) {
this(context, null);
}
public CircleViewPagerIndicator(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleViewPagerIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (isInEditMode()) return;
setOrientation(HORIZONTAL);
setBackgroundColor(getResources().getColor(android.R.color.transparent));
setPadding(20, 20, 20, 20);
setGravity(Gravity.CENTER);
}
public final void setViewPager(final ViewPager slideShow) {
// Preconditions.checkNotNull(slideShow);
// Verify.verify(slideShow.getAdapter() != null, "viewPager adapter == null");
mViewPager = slideShow;
onSetViewPager(slideShow);
slideShow.addOnPageChangeListener(this);
}
protected void onSetViewPager(final ViewPager slideShow) {
removeAllViews();
/*只有一个就不显示了*/
final int count = slideShow.getAdapter().getCount();
if (count == 1) return;
for (int index = 0; index < count; index++) {
addIndicator(index == slideShow.getCurrentItem());
}
}
protected final void addIndicator(boolean highlight) {
ImageView imageView = new ImageView(getContext());
imageView.setImageResource(highlight ? HIGHLIGHT_INDICATOR : NORMAL_INDICATOR);
LayoutParams params = new LayoutParams(16, 16);
params.rightMargin = 24;
addView(imageView, params);
}
@Override
public void onPageScrolled(int i, float v, int i2) {
}
@Override
public void onPageSelected(final int i) {
if (mViewPager == null) return;
final int count = getChildCount();
for (int index = 0; index < count; index++) {
final int indicator = index == i ? HIGHLIGHT_INDICATOR : NORMAL_INDICATOR;
final ImageView imageView = (ImageView) getChildAt(index);
imageView.setImageResource(indicator);
}
}
@Override
public void onPageScrollStateChanged(int i) {
}
}
indicator_slide_show和indicator_slideshow_checked 可以是两个圆点图片,也可以自己shape绘制两个圆形的drawable。
使用的时候,将CircleViewPagerIndicator添加到布局xml需要的位置,然后,在代码中初始化后,只需要调用
mIndicator.setViewPager(mViewPager);
就可以和相关的viewpager绑定了。
16.动态布局切换
fragment切换,以及view切换两种方式
package com.example.niejianjian.myapplication;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import com.example.niejianjian.myapplication.fragment.Fragment1;
import com.example.niejianjian.myapplication.fragment.Fragment2;
import com.example.niejianjian.myapplication.fragment.Fragment3;
/**
* Created by niejianjian on 2017/10/11.
*/
public class MyFragmentActicity extends FragmentActivity implements View.OnClickListener {
private Button mButton1, mButton2, mButton3;
private FragmentManager mFragmentManager;
private Fragment mFragment1, mFragment2, mFragment3;
private View mView1, mView2, mView3;
private FrameLayout mFrameLayout;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment);
mFrameLayout = (FrameLayout) findViewById(R.id.framelayout);
mButton1 = (Button) findViewById(R.id.btn1);
mButton2 = (Button) findViewById(R.id.btn2);
mButton3 = (Button) findViewById(R.id.btn3);
mButton1.setOnClickListener(this);
mButton2.setOnClickListener(this);
mButton3.setOnClickListener(this);
mFragment1 = new Fragment1();
mFragment2 = new Fragment2();
mFragment3 = new Fragment3();
mView1 = View.inflate(this, R.layout.fragment1, null);
mView2 = View.inflate(this, R.layout.fragment2, null);
mView3 = View.inflate(this, R.layout.fragment3, null);
mFragmentManager = getSupportFragmentManager();
// replaceFragment(mFragment1);
replaceView(mView1);
}
private void replaceFragment(Fragment fragment) {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.replace(R.id.framelayout, fragment);
// transaction.addToBackStack(null);
transaction.commit();
}
private void replaceView(View view) {
mFrameLayout.removeAllViews();
mFrameLayout.addView(view);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn1:
// replaceFragment(mFragment1);
replaceView(mView1);
break;
case R.id.btn2:
// replaceFragment(mFragment2);
replaceView(mView2);
break;
case R.id.btn3:
// replaceFragment(mFragment3);
replaceView(mView3);
break;
}
}
}
<?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"
android:orientation="horizontal">
<LinearLayout
android:layout_width="120dp"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="fragment1"/>
<Button
android:id="@+id/btn2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="fragment2"/>
<Button
android:id="@+id/btn3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="fragment3"/>
</LinearLayout>
<FrameLayout
android:id="@+id/framelayout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
Fragment1就是一个简单的Fragment,将其复制,分别命名为Fragment2,Fragment3.
public class Fragment1 extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment1, container, false);
}
}
<?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"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FF0000"
android:gravity="center"
android:text="这是第一个fragment"/>
</LinearLayout>