關於知識點的測試練習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>










發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章