关于知识点的测试练习demo,以及知识点的积累

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) {...}

MyService.java类中的内部类MyThread.java中,有这样一句代码:
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中指定androidprocess属性。

2).非常规方法:通过JNInative层去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;
	}
}


Contance.java:

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.自定义一个CustomViewextends View)类

2.编写values/attrs.xml,在其中编写styleableitem等标签元素

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>










  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值