├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── dictionaries │ └── Ray.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── Screenshot.jpg ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── rayzhang │ │ └── android │ │ └── materialdesign │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── rayzhang │ │ │ └── android │ │ │ └── materialdesign │ │ │ ├── AsyncTaskActivity.java │ │ │ ├── CollapsingActivity.java │ │ │ ├── CompressActivity.java │ │ │ ├── DialogActivity.java │ │ │ ├── ExecutorActivity.java │ │ │ ├── FacebookActivity.java │ │ │ ├── HandlerThreadActivity.java │ │ │ ├── LayoutActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── adapter │ │ │ ├── DemoAdapter.java │ │ │ └── itemdecoration │ │ │ │ └── LinearSectionDecoration.java │ │ │ ├── dialog │ │ │ ├── MySelfDialog.java │ │ │ └── NoticeDialog.java │ │ │ ├── intentservice │ │ │ ├── DownloadIntentService.java │ │ │ └── IntentServiceActivity.java │ │ │ ├── itemhelper │ │ │ ├── ItemMoveSwipeListener.java │ │ │ ├── ItemTouchHelperActivity.java │ │ │ ├── ItemTouchHelperAdapter.java │ │ │ └── RZItemTouchHelperCallback.java │ │ │ ├── onboarding │ │ │ └── OnboardingActivity.java │ │ │ └── widget │ │ │ └── RZIndicatorView.java │ └── res │ │ ├── drawable-hdpi │ │ ├── ic_arrow_back_white_24dp.png │ │ ├── ic_delete_forever_white_24dp.png │ │ ├── ic_favorite_white_24dp.png │ │ └── ic_google_play_24dp.png │ │ ├── drawable-mdpi │ │ ├── ic_arrow_back_white_24dp.png │ │ ├── ic_delete_forever_white_24dp.png │ │ ├── ic_favorite_white_24dp.png │ │ └── ic_google_play_24dp.png │ │ ├── drawable-xhdpi │ │ ├── ic_android.png │ │ ├── ic_arrow_back_white_24dp.png │ │ ├── ic_bird_shape.png │ │ ├── ic_chrome.png │ │ ├── ic_delete_forever_white_24dp.png │ │ ├── ic_facebook_45dp.png │ │ ├── ic_favorite_white_24dp.png │ │ ├── ic_google_play_24dp.png │ │ ├── ic_logout_45dp.png │ │ ├── ic_twitter.png │ │ └── ic_user_60dp.png │ │ ├── drawable-xxhdpi │ │ ├── ic_android.png │ │ ├── ic_arrow_back_white_24dp.png │ │ ├── ic_bird_shape.png │ │ ├── ic_chrome.png │ │ ├── ic_delete_forever_white_24dp.png │ │ ├── ic_facebook_45dp.png │ │ ├── ic_favorite_white_24dp.png │ │ ├── ic_google_play_24dp.png │ │ ├── ic_logout_45dp.png │ │ ├── ic_twitter.png │ │ └── ic_user_60dp.png │ │ ├── drawable-xxxhdpi │ │ ├── ic_arrow_back_white_24dp.png │ │ ├── ic_delete_forever_white_24dp.png │ │ ├── ic_favorite_white_24dp.png │ │ └── ic_google_play_24dp.png │ │ ├── drawable │ │ ├── dialog_myself_bg.xml │ │ ├── dialog_myself_left_but.xml │ │ ├── dialog_myself_right_but.xml │ │ └── twice_1.jpg │ │ ├── layout │ │ ├── activity_asynctask.xml │ │ ├── activity_collapsing.xml │ │ ├── activity_compress.xml │ │ ├── activity_dialog.xml │ │ ├── activity_executor.xml │ │ ├── activity_facebook.xml │ │ ├── activity_handler_thread.xml │ │ ├── activity_intent_service.xml │ │ ├── activity_item_touch_helper.xml │ │ ├── activity_layout.xml │ │ ├── activity_main.xml │ │ ├── activity_onboarding.xml │ │ ├── adapter_item.xml │ │ ├── dialog_myself.xml │ │ ├── fragment_onboarding.xml │ │ ├── include_linearlayout.xml │ │ ├── include_toolbar.xml │ │ └── viewstub_img.xml │ │ ├── menu │ │ └── toolbar_menu.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v19 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── rayzhang │ └── android │ └── materialdesign │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/dictionaries/Ray.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 26 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 53 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Introduction 介紹 2 | ==== 3 | This Demo is introduction. Ex:FloatingActionButton, ToolBar, ...else 4 |
該Demo會不定期更新,詳細使用說明請連結至右邊網址→[MyBlog](https://rayzhangweb.wordpress.com/ "Designer:RayZhang") 5 | 6 | Directory 7 | ==== 8 | * [2017-01-08---MATERIAL DESIGN – FLOATING ACTION BUTTONS](https://rayzhangweb.wordpress.com/2017/01/08/material-design-floating-action-buttons-%E4%BD%BF%E7%94%A8/) 9 | * [2017-02-01---MATERIAL DESIGN – TOOLBAR](https://rayzhangweb.wordpress.com/2017/02/01/material-design-toolbar-%E4%BD%BF%E7%94%A8/) 10 | * [2017-02-19---ANDROID LIBRARY上傳至JCENTER,一次就上手](https://rayzhangweb.wordpress.com/2017/02/19/android-library%E4%B8%8A%E5%82%B3%E8%87%B3jcenter%EF%BC%8C%E4%B8%80%E6%AC%A1%E5%B0%B1%E4%B8%8A%E6%89%8B/) 11 | * [2017-03-12---MATERIAL DESIGN – APPBARLAYOUT & COLLAPSINGTOOLBARLAYOUT](https://rayzhangweb.wordpress.com/2017/03/12/material-design-appbarlayout-collapsingtoolbarlayout-%E4%BD%BF%E7%94%A8/) 12 | * [2017-03-26---MATERIAL DESIGN – CardView](https://rayzhangweb.wordpress.com/2017/03/26/material-design-cardview-%E4%BD%BF%E7%94%A8/?frame-nonce=3803e6640f) 13 | * [2017-04-16---AlertDialig and DialogFragment](https://rayzhangweb.wordpress.com/2017/04/16/android-dialog-and-dialogfragment/) 14 | * [2017-04-30---ANDROID - 佈局優化Include、Merge、Viewstub](https://rayzhangweb.wordpress.com/2017/04/30/android-%E4%BD%88%E5%B1%80%E5%84%AA%E5%8C%96include%E3%80%81merge%E3%80%81viewstub/) 15 | * [2017-05-07---ANDROID - 座標系統,你知多少?](https://rayzhangweb.wordpress.com/2017/05/07/android-%E5%BA%A7%E6%A8%99%E7%B3%BB%E7%B5%B1%EF%BC%8C%E4%BD%A0%E7%9F%A5%E5%A4%9A%E5%B0%91/?preview_id=1257&preview_nonce=29d3f6d5c1) 16 | * [2017-05-21---ANDROID - STEP BY STEP 教你做出MATERIAL DESIGN風格 導覽頁](https://rayzhangweb.wordpress.com/2017/05/21/android-step-by-step-%E6%95%99%E4%BD%A0%E5%81%9A%E5%87%BAmaterial-design%E9%A2%A8%E6%A0%BC-%E5%B0%8E%E8%A6%BD%E9%A0%81/) 17 | * [2017-05-29---ANDROID - 簡單為RecycleView添加分隔線吧](https://rayzhangweb.wordpress.com/2017/05/29/android-%E7%B0%A1%E5%96%AE%E7%82%BArecycleview%E6%B7%BB%E5%8A%A0%E5%88%86%E9%9A%94%E7%B7%9A%E5%90%A7/?preview_id=1505&preview_nonce=1f88f79184) 18 | * [2017-06-11---ANDROID - 為RecycleView添加分類群組](https://rayzhangweb.wordpress.com/2017/06/11/android-%E7%82%BArecycle%E6%B7%BB%E5%8A%A0%E5%88%86%E9%A1%9E%E7%BE%A4%E7%B5%84%E5%90%A7/?preview_id=1642&preview_nonce=a2063df513) 19 | * [2017-06-24---ANDROID 一步一步,教你用FACEBOOK SDK,實現登入](https://rayzhangweb.wordpress.com/2017/06/24/android-%E4%B8%80%E6%AD%A5%E4%B8%80%E6%AD%A5%EF%BC%8C%E6%95%99%E4%BD%A0%E7%94%A8facebook-sdk%EF%BC%8C%E5%AF%A6%E7%8F%BE%E7%99%BB%E5%85%A5/) 20 | * [2017-07-08---ANDROID – ItemTouchHelper讓RecycleView item動起來吧!](https://rayzhangweb.wordpress.com/2017/07/08/android-itemtouchhelper%E8%AE%93recycleview-item%E5%8B%95%E8%B5%B7%E4%BE%86%E5%90%A7/) 21 | * [2017-07-27---ANDROID – 關於AsyncTask](https://rayzhangweb.wordpress.com/2017/07/27/android-%E9%97%9C%E6%96%BCasynctask/) 22 | * [2017-08-05---ANDROID – 關於IntentService](https://rayzhangweb.wordpress.com/2017/08/05/android-%E9%97%9C%E6%96%BCintentservice/) 23 | * [2017-08-12---ANDROID – 關於HandlerThread](https://rayzhangweb.wordpress.com/2017/08/12/android-%E9%97%9C%E6%96%BChandlerthread/) 24 | * [2017-08-27---ANDROID – 關於ThreadPoolExecutor](https://rayzhangweb.wordpress.com/2017/08/27/android-%E9%97%9C%E6%96%BC%E3%80%8Cthreadpoolexecutor%E3%80%8D/) 25 | * [2017-09-11---ANDROID – BITMAP之佔用記憶體大小](https://rayzhangweb.wordpress.com/2017/09/11/android-bitmap%E4%B9%8B%E4%BD%94%E7%94%A8%E8%A8%98%E6%86%B6%E9%AB%94%E5%A4%A7%E5%B0%8F/) 26 | * [2017-10-15---ANDROID – Bitmap with Compress](https://rayzhangweb.wordpress.com/2017/10/15/android-bitmap-with-compress/) 27 |
28 | 29 | Contact me 30 | ==== 31 | If you have any question, you can send mail for me.
32 | E-mail→→→ 33 | -------------------------------------------------------------------------------- /Screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/Screenshot.jpg -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.3" 6 | defaultConfig { 7 | applicationId "com.rayzhang.android.materialdesign" 8 | minSdkVersion 16 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | // FB 28 | // Glide 29 | compile 'com.android.support:appcompat-v7:25.3.1' 30 | compile 'com.android.support:design:25.3.1' 31 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 32 | compile 'com.android.support:cardview-v7:25.3.1' 33 | compile 'com.facebook.android:facebook-android-sdk:4.23.0' 34 | compile 'com.github.bumptech.glide:glide:3.7.0' 35 | testCompile 'junit:junit:4.12' 36 | } 37 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in D:\AppData\Android\SDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/rayzhang/android/materialdesign/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.rayzhang.android.materialdesign", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | // 網路權限(要添加) 5 | 6 | 7 | 8 | 9 | 15 | 16 | 17 | 18 | 21 | 22 | 26 | 27 | 31 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 57 | 58 | 61 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 81 | 82 | 83 | 84 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/AsyncTaskActivity.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.os.AsyncTask; 6 | import android.os.Bundle; 7 | import android.support.annotation.Nullable; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.util.Log; 10 | import android.view.View; 11 | import android.widget.Button; 12 | import android.widget.ImageView; 13 | import android.widget.TextView; 14 | 15 | import java.io.ByteArrayOutputStream; 16 | import java.io.IOException; 17 | import java.io.InputStream; 18 | import java.net.HttpURLConnection; 19 | import java.net.URL; 20 | import java.util.ArrayList; 21 | import java.util.Locale; 22 | 23 | /** 24 | * Created by Ray on 2017/7/9. 25 | */ 26 | 27 | public class AsyncTaskActivity extends AppCompatActivity implements View.OnClickListener { 28 | private static final String TAG = AsyncTaskActivity.class.getSimpleName(); 29 | private ImageView mImgView, imageView_Two; 30 | private TextView mText_One; 31 | 32 | private ArrayList taskList; 33 | 34 | @Override 35 | protected void onCreate(@Nullable Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | setContentView(R.layout.activity_asynctask); 38 | 39 | mImgView = (ImageView) findViewById(R.id.mImgView); 40 | imageView_Two = (ImageView) findViewById(R.id.imageView_Two); 41 | Button mDownloadBut = (Button) findViewById(R.id.mDownloadBut); 42 | Button mCancelBut = (Button) findViewById(R.id.mCancelBut); 43 | mText_One = (TextView) findViewById(R.id.mText_One); 44 | mDownloadBut.setOnClickListener(this); 45 | mCancelBut.setOnClickListener(this); 46 | 47 | taskList = new ArrayList<>(); 48 | } 49 | 50 | @Override 51 | public void onClick(View view) { 52 | switch (view.getId()) { 53 | case R.id.mDownloadBut: 54 | /** 55 | * AsyncTask.THREAD_POOL_EXECUTOR : 允許多個任務,在同個執行緒池,不保證順序性 56 | * AsyncTask.SERIAL_EXECUTOR : 執行單一任務,順序執行的 57 | * execute() : default is AsyncTask.SERIAL_EXECUTOR 58 | */ 59 | //new DownloadAsyncTask().execute("https://i.ytimg.com/vi/dmRgNR3WbHc/maxresdefault.jpg", 60 | // "https://cdn.hk01.com/media/images/582792/xlarge/e152f34b18d92f4595f84b7ee016ccab.jpg"); 61 | DownloadAsyncTask task_1 = new DownloadAsyncTask(0); 62 | DownloadAsyncTask task_2 = new DownloadAsyncTask(1); 63 | // 剛初始化完成,尚未執行任務 64 | Log.d(TAG, "TASK init:" + task_1.getStatus()); 65 | 66 | // 順序任務 67 | //task_1.execute("https://i.ytimg.com/vi/dmRgNR3WbHc/maxresdefault.jpg"); 68 | //task_2.execute("https://cdn.hk01.com/media/images/582792/xlarge/e152f34b18d92f4595f84b7ee016ccab.jpg"); 69 | // 並行任務 70 | task_1.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 71 | "https://i.ytimg.com/vi/dmRgNR3WbHc/maxresdefault.jpg"); 72 | task_2.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 73 | "https://cdn.hk01.com/media/images/582792/xlarge/e152f34b18d92f4595f84b7ee016ccab.jpg"); 74 | taskList.add(task_1); 75 | taskList.add(task_2); 76 | break; 77 | case R.id.mCancelBut: 78 | // cancel : 調用 doInBackground() → onCancelled() → onCancelled(T t) 79 | // true : 會立即取消任務 80 | // false : 不會立即取消任務 81 | if (taskList.size() > 0) { 82 | for (DownloadAsyncTask task : taskList) { 83 | task.cancel(false); 84 | } 85 | taskList.clear(); 86 | } 87 | break; 88 | } 89 | } 90 | 91 | @Override 92 | protected void onDestroy() { 93 | if (taskList.size() > 0) { 94 | for (DownloadAsyncTask task : taskList) { 95 | task.cancel(true); 96 | } 97 | taskList.clear(); 98 | } 99 | super.onDestroy(); 100 | } 101 | 102 | /** 103 | * 使用異步任務的方式 104 | * 1-1.聲明一個class並繼承AsyncTask 並聲明三個參數類型(若沒有要聲明參數,則要以Void表示) 105 | * 1-2.Not all types are always used by an asynchronous task. To mark a type as unused, simply use the type Void 106 | * 2-1.第1個參數表示要執行的任務,通常都是網址 107 | * 2-2.第2個參數表示任務的黨前進度 108 | * 2-3.第3個參數表示當任務完成後,要返回的型別 109 | */ 110 | private class DownloadAsyncTask extends AsyncTask { 111 | private int tag = 0; 112 | 113 | public DownloadAsyncTask(int tag) { 114 | this.tag = tag; 115 | } 116 | 117 | @Override 118 | protected void onPreExecute() { 119 | super.onPreExecute(); 120 | Log.d(TAG, "onPreExecute status:" + getStatus()); 121 | } 122 | 123 | @Override 124 | protected Bitmap[] doInBackground(String... params) { 125 | Log.d(TAG, "doInBackground status:" + getStatus()); 126 | // 先休眠3秒,在執行 127 | try { 128 | Thread.sleep(1500); 129 | } catch (InterruptedException e) { 130 | e.printStackTrace(); 131 | } 132 | // 判斷是否取消任務 133 | if (getStatus() == Status.RUNNING && isCancelled()) { 134 | Log.d(TAG, "doInBackground isCancelled :" + isCancelled()); 135 | return null; 136 | } 137 | Bitmap[] bitmaps = new Bitmap[params.length]; 138 | InputStream is = null; 139 | ByteArrayOutputStream os = null; 140 | try { 141 | for (int i = 0, j = bitmaps.length; i < j; i++) { 142 | URL url = new URL(params[i]); 143 | HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); 144 | httpURLConnection.setConnectTimeout(15000); 145 | httpURLConnection.setReadTimeout(15000); 146 | httpURLConnection.setDoInput(true); 147 | httpURLConnection.setRequestMethod("GET"); 148 | 149 | int responseCode = httpURLConnection.getResponseCode(); 150 | if (responseCode == 200) { 151 | is = httpURLConnection.getInputStream(); 152 | os = new ByteArrayOutputStream(); 153 | byte[] buffer = new byte[1024]; 154 | int len; 155 | long totalLen = httpURLConnection.getContentLength(); 156 | long nowLen = 0; 157 | while ((len = is.read(buffer)) != -1) { 158 | nowLen += len; 159 | int value = (int) ((nowLen / (float) totalLen) * 100); 160 | // 呼叫publishProgress -->去自動更新目前的進度 161 | publishProgress(value); 162 | os.write(buffer, 0, len); 163 | } 164 | bitmaps[i] = BitmapFactory.decodeByteArray(os.toByteArray(), 0, os.toByteArray().length); 165 | } 166 | } 167 | } catch (Exception e) { 168 | Log.d(TAG, "Exception:" + e.toString()); 169 | } finally { 170 | try { 171 | if (os != null) { 172 | os.flush(); 173 | os.close(); 174 | } 175 | if (is != null) { 176 | is.close(); 177 | } 178 | } catch (IOException e) { 179 | e.printStackTrace(); 180 | } 181 | } 182 | return bitmaps; 183 | } 184 | 185 | @Override 186 | protected void onProgressUpdate(Integer... values) { 187 | super.onProgressUpdate(values); 188 | Log.d(TAG, String.format(Locale.TAIWAN, "onProgressUpdate value:%d", values[0])); 189 | } 190 | 191 | @Override 192 | protected void onPostExecute(Bitmap[] bitmaps) { 193 | super.onPostExecute(bitmaps); 194 | // 待任務都完成後,才會調用此方法 195 | mText_One.setText("onPostExecute bitmap:" + bitmaps.length + " status:" + getStatus() + " isCanceled:" + isCancelled()); 196 | if (tag == 0) { 197 | mImgView.setImageBitmap(bitmaps[0]); 198 | } else { 199 | imageView_Two.setImageBitmap(bitmaps[0]); 200 | } 201 | } 202 | 203 | @Override 204 | protected void onCancelled() { 205 | super.onCancelled(); 206 | Log.d(TAG, "onCancelled status:" + getStatus() + " isCanceled:" + isCancelled()); 207 | } 208 | 209 | @Override 210 | protected void onCancelled(Bitmap[] bitmaps) { 211 | super.onCancelled(bitmaps); 212 | 213 | mText_One.setText("cancelled bitmaps:" + bitmaps + " status:" + getStatus() + " isCanceled:" + isCancelled()); 214 | if (bitmaps != null) { 215 | mImgView.setImageBitmap(bitmaps[0]); 216 | imageView_Two.setImageBitmap(bitmaps[1]); 217 | } 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/CollapsingActivity.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign; 2 | 3 | import android.graphics.Color; 4 | import android.graphics.Typeface; 5 | import android.os.Bundle; 6 | import android.support.design.widget.AppBarLayout; 7 | import android.support.design.widget.CollapsingToolbarLayout; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.support.v7.widget.DefaultItemAnimator; 10 | import android.support.v7.widget.LinearLayoutManager; 11 | import android.support.v7.widget.RecyclerView; 12 | import android.support.v7.widget.Toolbar; 13 | import android.view.View; 14 | 15 | import com.rayzhang.android.materialdesign.adapter.DemoAdapter; 16 | import com.rayzhang.android.materialdesign.adapter.itemdecoration.LinearSectionDecoration; 17 | 18 | import java.util.ArrayList; 19 | import java.util.Collections; 20 | import java.util.List; 21 | 22 | public class CollapsingActivity extends AppCompatActivity { 23 | /** 24 | * CollapsingToolbarLayout use 25 | */ 26 | private AppBarLayout mAppBarLayout; 27 | private CollapsingToolbarLayout mCollapsLayout; 28 | private Toolbar mToolBar; 29 | private RecyclerView mRecyView; 30 | 31 | @Override 32 | protected void onCreate(final Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.activity_collapsing); 35 | 36 | mAppBarLayout = (AppBarLayout) findViewById(R.id.mAppBarLayout); 37 | mCollapsLayout = (CollapsingToolbarLayout) findViewById(R.id.mCollaspLayout); 38 | mToolBar = (Toolbar) findViewById(R.id.mToolBar); 39 | setSupportActionBar(mToolBar); 40 | 41 | /*mAppBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { 42 | // https://codedump.io/share/x8JwlFS66glv/1/show-collapsingtoolbarlayout-title-only-when-collapsed 43 | boolean isShow = false; 44 | int scrollRange = -1; 45 | 46 | @Override 47 | public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { 48 | if (scrollRange == -1) scrollRange = appBarLayout.getTotalScrollRange(); 49 | if (scrollRange + verticalOffset == 0) { 50 | mToolBar.setTitle("CollapsingToolbarLayout"); 51 | isShow = true; 52 | } else if (isShow) { 53 | mToolBar.setTitle(""); 54 | isShow = false; 55 | } 56 | } 57 | });*/ 58 | mCollapsLayout.setTitle("Collapsing"); 59 | mCollapsLayout.setCollapsedTitleTypeface(Typeface.SERIF); 60 | mCollapsLayout.setCollapsedTitleTextColor(Color.WHITE); 61 | mCollapsLayout.setExpandedTitleTypeface(Typeface.SERIF); 62 | mCollapsLayout.setExpandedTitleColor(Color.TRANSPARENT); 63 | 64 | mRecyView = (RecyclerView) findViewById(R.id.mRecyView); 65 | mRecyView.setItemAnimator(new DefaultItemAnimator()); 66 | mRecyView.setHasFixedSize(true); 67 | RecyclerView.LayoutManager manager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); 68 | mRecyView.setLayoutManager(manager); 69 | 70 | // 資料來源 71 | final List list = new ArrayList<>(); 72 | for (int i = 1, j = 100; i <= j; i++) { 73 | list.add("" + i); 74 | } 75 | // 將List做分組排序 76 | Collections.sort(list); 77 | /** 78 | * 設置RecycleView的Divider 79 | */ 80 | //mRecyView.addItemDecoration(new LinearSectionDecoration(1, Color.argb(255, 0, 102, 255))); 81 | /** 82 | * 設置RecycleView的Divider(include section) 83 | */ 84 | mRecyView.addItemDecoration(new LinearSectionDecoration(50, 1, Color.argb(255, 0, 102, 255), 85 | new LinearSectionDecoration.LinearSectionCallback() { 86 | @Override 87 | public String getItemStr(int poisition) { 88 | // 回傳每個Item的第1個字 89 | return list.get(poisition).substring(0, 1); 90 | } 91 | })); 92 | /** 93 | * 設置RecyclerView的Adapter 94 | */ 95 | DemoAdapter adapter = new DemoAdapter(list); 96 | mRecyView.setAdapter(adapter); 97 | adapter.setOnItemClickListener(new DemoAdapter.onItemClickListener() { 98 | @Override 99 | public void onItemClick(View view) { 100 | //Intent i = new Intent(CollapsingActivity.this, MainActivity.class); 101 | //startActivity(i); 102 | } 103 | }); 104 | } 105 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/CompressActivity.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign; 2 | 3 | import android.content.Intent; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Matrix; 7 | import android.net.Uri; 8 | import android.os.Bundle; 9 | import android.os.Environment; 10 | import android.support.annotation.Nullable; 11 | import android.support.v7.app.AppCompatActivity; 12 | import android.util.Log; 13 | import android.view.View; 14 | import android.widget.Button; 15 | import android.widget.ImageView; 16 | import android.widget.TextView; 17 | 18 | import java.io.ByteArrayOutputStream; 19 | import java.io.File; 20 | import java.io.FileOutputStream; 21 | import java.io.IOException; 22 | import java.io.OutputStream; 23 | import java.text.SimpleDateFormat; 24 | import java.util.Date; 25 | import java.util.Locale; 26 | 27 | /** 28 | * Created by Ray on 2017/10/15. 29 | * CompressActivity 30 | */ 31 | 32 | public class CompressActivity extends AppCompatActivity { 33 | private static final String TAG = CompressActivity.class.getSimpleName(); 34 | 35 | private TextView mTextAfterView; 36 | private ImageView mImgAfterView; 37 | 38 | @Override 39 | protected void onCreate(@Nullable Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | setContentView(R.layout.activity_compress); 42 | 43 | TextView mTextBeforeView = (TextView) findViewById(R.id.mTextBeforeView); 44 | mTextAfterView = (TextView) findViewById(R.id.mTextAfterView); 45 | ImageView mImgBeforeView = (ImageView) findViewById(R.id.mImgBeforeView); 46 | mImgAfterView = (ImageView) findViewById(R.id.mImgAfterView); 47 | Button mMatrixBut = (Button) findViewById(R.id.mMatrixBut); 48 | Button mRGBBut = (Button) findViewById(R.id.mRGBBut); 49 | Button mSampleBut = (Button) findViewById(R.id.mSampleBut); 50 | 51 | log("###############################"); 52 | // /05.jpg(橫的) 53 | final String filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath() + "/05.jpg"; 54 | final Bitmap bitmap = BitmapFactory.decodeFile(filePath); 55 | // 從硬碟讀取的記憶體大小 = 10664000 (10.16MB) (2000 * 1333) 56 | log(String.format(Locale.TAIWAN, "Disk ByteCount:%d", bitmap.getByteCount())); 57 | log(String.format(Locale.TAIWAN, "Disk Width:%d Heigth:%d", bitmap.getWidth(), bitmap.getHeight())); 58 | mTextBeforeView.setText(String.format(Locale.TAIWAN, "壓縮前:w:%dpx h:%dpx size:%.2f MB", 59 | bitmap.getWidth(), bitmap.getHeight(), convertMB(bitmap.getByteCount()))); 60 | mImgBeforeView.setImageBitmap(bitmap); 61 | 62 | mMatrixBut.setOnClickListener(new View.OnClickListener() { 63 | @Override 64 | public void onClick(View v) { 65 | bitmapCompressByMatrix(bitmap, 0.45f); 66 | } 67 | }); 68 | mRGBBut.setOnClickListener(new View.OnClickListener() { 69 | @Override 70 | public void onClick(View v) { 71 | bitmapCompressByRGB565(filePath); 72 | } 73 | }); 74 | mSampleBut.setOnClickListener(new View.OnClickListener() { 75 | @Override 76 | public void onClick(View v) { 77 | bitmapCompressByFitSize(filePath, 1000, 650); 78 | } 79 | }); 80 | } 81 | 82 | private void bitmapCompressByMatrix(Bitmap bitmap, float scale) { 83 | // Use matrix 改變圖片長、寬 84 | Matrix matrix = new Matrix(); 85 | // 縮小的比例 86 | matrix.setScale(scale, scale); 87 | Bitmap after = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); 88 | bitmap.recycle(); 89 | log("###############################"); 90 | log(String.format(Locale.TAIWAN, "Matrix ByteCount:%d", after.getByteCount())); 91 | log(String.format(Locale.TAIWAN, "Matrix Width:%d Heigth:%d", after.getWidth(), after.getHeight())); 92 | mTextAfterView.setText(String.format(Locale.TAIWAN, "Matrix 壓縮後:w:%dpx h:%dpx size:%.2f MB", 93 | after.getWidth(), after.getHeight(), convertMB(after.getByteCount()))); 94 | mImgAfterView.setImageBitmap(after); 95 | } 96 | 97 | private void bitmapCompressByRGB565(String filePath) { 98 | // Use RGB_565 改變圖片質量 99 | // 在andorid中系統是預設使用ARGB_8888(Each pixel is stored on 4 bytes,每個畫素採用4bytes) 100 | // 而RGB_565(Each pixel is stored on 2 bytes,每個畫素採用2bytes),所以2者大小相差2倍 101 | // 如果有透明的需求,則該方式是不適合使用。 102 | // 當然也還有其他質量的選擇,但因畫質太糟故不建議使用。 103 | BitmapFactory.Options options = new BitmapFactory.Options(); 104 | options.inPreferredConfig = Bitmap.Config.RGB_565; 105 | Bitmap after = BitmapFactory.decodeFile(filePath, options); 106 | log("###############################"); 107 | log(String.format(Locale.TAIWAN, "RGB565 ByteCount:%d", after.getByteCount())); 108 | log(String.format(Locale.TAIWAN, "RGB565 Width:%d Heigth:%d", after.getWidth(), after.getHeight())); 109 | mTextAfterView.setText(String.format(Locale.TAIWAN, "RGB_565 壓縮後:w:%dpx h:%dpx size:%.2f MB", 110 | after.getWidth(), after.getHeight(), convertMB(after.getByteCount()))); 111 | mImgAfterView.setImageBitmap(after); 112 | } 113 | 114 | private void bitmapCompressByFitSize(String filePath, float reqWidth, float reqHeight) { 115 | // Use inSampleSize 改變圖片取樣率 116 | // 該方式也是大多數人所知道的方式 117 | BitmapFactory.Options options = new BitmapFactory.Options(); 118 | options.inJustDecodeBounds = true; 119 | BitmapFactory.decodeFile(filePath, options); 120 | options.inSampleSize = calculateFitSize((int) reqWidth, (int) reqHeight, options); 121 | options.inJustDecodeBounds = false; 122 | Bitmap after = BitmapFactory.decodeFile(filePath, options); 123 | log("###############################"); 124 | log(String.format(Locale.TAIWAN, "inSampleSize ByteCount:%d", after.getByteCount())); 125 | log(String.format(Locale.TAIWAN, "inSampleSize Width:%d Heigth:%d", after.getWidth(), after.getHeight())); 126 | mTextAfterView.setText(String.format(Locale.TAIWAN, "inSampleSize 壓縮後:w:%dpx h:%dpx \nsize:%.2f MB", 127 | after.getWidth(), after.getHeight(), convertMB(after.getByteCount()))); 128 | mImgAfterView.setImageBitmap(after); 129 | } 130 | 131 | private int calculateFitSize(int reqWidth, int reqHeight, BitmapFactory.Options options) { 132 | // 原始圖片的寬高 133 | final int height = options.outHeight; 134 | final int width = options.outWidth; 135 | int inSampleSize = 1; 136 | if (height > reqHeight || width > reqWidth) { 137 | final int halfHeight = height / 2; 138 | final int halfWidth = width / 2; 139 | // 在保證解析出的bitmap寬高分別大於目標尺寸寬高的前提下,取可能的inSampleSize的最大值 140 | while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { 141 | inSampleSize *= 2; 142 | } 143 | } 144 | return inSampleSize; 145 | } 146 | 147 | private void saveImage(Bitmap bitmap) { 148 | String imgName = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.TAIWAN).format(new Date()); 149 | File filesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM); 150 | File imageFile = new File(filesDir, imgName + ".jpg"); 151 | 152 | OutputStream os = null; 153 | try { 154 | os = new FileOutputStream(imageFile); 155 | bitmap.compress(Bitmap.CompressFormat.JPEG, 85, os); 156 | scanPhoto(imageFile.getAbsolutePath()); 157 | } catch (Exception e) { 158 | Log.e(getClass().getSimpleName(), "Error save bitmap:", e); 159 | } finally { 160 | if (os != null) { 161 | try { 162 | os.close(); 163 | os.flush(); 164 | } catch (IOException e) { 165 | e.printStackTrace(); 166 | } 167 | } 168 | } 169 | } 170 | 171 | private void scanPhoto(String imgFilePath) { 172 | Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); 173 | File file = new File(imgFilePath); 174 | Uri contentUri = Uri.fromFile(file); 175 | mediaScanIntent.setData(contentUri); 176 | getApplicationContext().sendBroadcast(mediaScanIntent); 177 | } 178 | 179 | private float convertMB(int size) { 180 | return (float) size / (1024f * 1024f); 181 | } 182 | 183 | private void log(String str) { 184 | Log.d(TAG, str); 185 | } 186 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/DialogActivity.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign; 2 | 3 | import android.app.Fragment; 4 | import android.app.FragmentTransaction; 5 | import android.content.DialogInterface; 6 | import android.os.Bundle; 7 | import android.support.v4.app.DialogFragment; 8 | import android.support.v7.app.AlertDialog; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.util.Log; 11 | import android.view.View; 12 | import android.widget.Button; 13 | 14 | import com.rayzhang.android.materialdesign.dialog.MySelfDialog; 15 | import com.rayzhang.android.materialdesign.dialog.NoticeDialog; 16 | 17 | public class DialogActivity extends AppCompatActivity implements View.OnClickListener, NoticeDialog.NoticeDialogListener, 18 | MySelfDialog.MySelfDialogListener { 19 | /** 20 | * Dialog Demo 21 | */ 22 | private static final String TAG = DialogActivity.class.getSimpleName(); 23 | private Button mButAlert, mButFragment, mButSelf; 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_dialog); 29 | 30 | initView(); 31 | } 32 | 33 | private void initView() { 34 | mButAlert = (Button) findViewById(R.id.mButAlert); 35 | mButFragment = (Button) findViewById(R.id.mButFragment); 36 | mButSelf = (Button) findViewById(R.id.mButSelf); 37 | 38 | mButAlert.setOnClickListener(this); 39 | mButFragment.setOnClickListener(this); 40 | mButSelf.setOnClickListener(this); 41 | } 42 | 43 | @Override 44 | public void onClick(View v) { 45 | switch (v.getId()) { 46 | case R.id.mButAlert: 47 | // Use AlertDialog 48 | showAlertDailog(); 49 | break; 50 | case R.id.mButFragment: 51 | // Use DialogFragment 52 | showDialogFragment(); 53 | break; 54 | case R.id.mButSelf: 55 | // Use DialogFragment by myself 56 | showMySelfDialog(); 57 | break; 58 | } 59 | } 60 | 61 | private void showAlertDailog() { 62 | AlertDialog dialog = new AlertDialog.Builder(DialogActivity.this) 63 | .setTitle("離開此頁面") 64 | .setMessage("是否要離開?") 65 | .setIcon(R.drawable.ic_bird_shape) 66 | .setCancelable(false) 67 | .setNegativeButton("再等等", new DialogInterface.OnClickListener() { 68 | @Override 69 | public void onClick(DialogInterface dialog, int which) { 70 | dialog.dismiss(); 71 | logStr("witch:" + which); 72 | } 73 | }) 74 | .setNeutralButton("忽略", new DialogInterface.OnClickListener() { 75 | @Override 76 | public void onClick(DialogInterface dialog, int which) { 77 | dialog.dismiss(); 78 | logStr("witch:" + which); 79 | } 80 | }) 81 | .setPositiveButton("好", new DialogInterface.OnClickListener() { 82 | @Override 83 | public void onClick(DialogInterface dialog, int which) { 84 | dialog.dismiss(); 85 | logStr("witch:" + which); 86 | } 87 | }).create(); 88 | dialog.show(); 89 | } 90 | 91 | private void showDialogFragment() { 92 | NoticeDialog dialog = NoticeDialog.instance("離開此頁面"); 93 | dialog.show(getSupportFragmentManager(), "NoticeDialog"); 94 | } 95 | 96 | private void showMySelfDialog() { 97 | // 可以透過FragmentTransaction來管理 98 | // DialogFragment.show() will take care of adding the fragment 99 | // in a transaction. We also want to remove any currently showing 100 | // dialog, so make our own transaction and take care of that here. 101 | FragmentTransaction ft = getFragmentManager().beginTransaction(); 102 | Fragment prev = getFragmentManager().findFragmentByTag("MySelfDialog"); 103 | if (prev != null) { 104 | ft.remove(prev); 105 | } 106 | ft.addToBackStack(null).commit(); 107 | 108 | // Create and show the dialog. 109 | MySelfDialog dialog = MySelfDialog.instance("離開此頁面"); 110 | dialog.show(getSupportFragmentManager(), "MySelfDialog"); 111 | } 112 | 113 | @Override 114 | public void onDialogPositiveClick(DialogFragment dialog) { 115 | dialog.dismiss(); 116 | logStr("onDialogPositiveClick"); 117 | } 118 | 119 | @Override 120 | public void onDialogNegativeClick(DialogFragment dialog) { 121 | dialog.dismiss(); 122 | logStr("onDialogNegativeClick"); 123 | } 124 | 125 | @Override 126 | public void onDialogOKClick(DialogFragment dialog) { 127 | dialog.dismiss(); 128 | logStr("onDialogOKClick"); 129 | } 130 | 131 | @Override 132 | public void onDialogCancelClick(DialogFragment dialog) { 133 | dialog.dismiss(); 134 | logStr("onDialogCancelClick"); 135 | } 136 | 137 | private void logStr(String str) { 138 | Log.d(TAG, str); 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/ExecutorActivity.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign; 2 | 3 | import android.os.Bundle; 4 | import android.os.SystemClock; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.util.Log; 7 | import android.view.View; 8 | 9 | import java.text.SimpleDateFormat; 10 | import java.util.Date; 11 | import java.util.Locale; 12 | import java.util.concurrent.ExecutorService; 13 | import java.util.concurrent.Executors; 14 | import java.util.concurrent.ScheduledExecutorService; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | /** 18 | * 執行緒池的分類 19 | */ 20 | public class ExecutorActivity extends AppCompatActivity { 21 | private static final String TAG = ExecutorActivity.class.getSimpleName(); 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setContentView(R.layout.activity_executor); 27 | 28 | findViewById(R.id.mFixBut).setOnClickListener(new View.OnClickListener() { 29 | @Override 30 | public void onClick(View v) { 31 | fixedThread(); 32 | } 33 | }); 34 | findViewById(R.id.mCacheBut).setOnClickListener(new View.OnClickListener() { 35 | @Override 36 | public void onClick(View v) { 37 | cacheThread(); 38 | } 39 | }); 40 | findViewById(R.id.mScheduleBut).setOnClickListener(new View.OnClickListener() { 41 | @Override 42 | public void onClick(View v) { 43 | scheduledThread(); 44 | } 45 | }); 46 | findViewById(R.id.mSingleBut).setOnClickListener(new View.OnClickListener() { 47 | @Override 48 | public void onClick(View v) { 49 | singleThread(); 50 | } 51 | }); 52 | } 53 | 54 | private void fixedThread() { 55 | // 每次執行最多4個,但不保證順序性 56 | ExecutorService fixed = Executors.newFixedThreadPool(4); 57 | Log.d(TAG, "CurrentTime:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.TAIWAN).format(new Date())); 58 | for (int i = 1; i <= 8; i++) { 59 | Task task = new Task("Fixed " + i); 60 | fixed.execute(task); 61 | } 62 | } 63 | 64 | private void cacheThread() { 65 | // 無次數限制,但不保證順序性 66 | ExecutorService cache = Executors.newCachedThreadPool(); 67 | Log.d(TAG, "CurrentTime:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.TAIWAN).format(new Date())); 68 | for (int i = 1; i <= 10; i++) { 69 | Task task = new Task("Cache " + i); 70 | cache.execute(task); 71 | } 72 | } 73 | 74 | private void scheduledThread() { 75 | // 定時性的任務 76 | ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(4); 77 | Log.d(TAG, "CurrentTime:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.TAIWAN).format(new Date())); 78 | Task task = new Task("Scheduled"); 79 | // 2s後執行 80 | scheduled.schedule(task, 2, TimeUnit.SECONDS); 81 | // 延遲1s後,每2s執行1次 82 | scheduled.scheduleAtFixedRate(task, 1, 2, TimeUnit.SECONDS); 83 | } 84 | 85 | private void singleThread() { 86 | // 每次只執行1個任務,有順序性 87 | ExecutorService single = Executors.newSingleThreadExecutor(); 88 | Log.d(TAG, "CurrentTime:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.TAIWAN).format(new Date())); 89 | for (int i = 1; i < 5; i++) { 90 | Task task = new Task("SingleThread " + i); 91 | single.execute(task); 92 | } 93 | } 94 | 95 | private static class Task implements Runnable { 96 | private String taskName; 97 | 98 | private Task(String taskName) { 99 | this.taskName = taskName; 100 | } 101 | 102 | @Override 103 | public void run() { 104 | SystemClock.sleep(1000); 105 | Log.d(TAG, "TaskName:" + taskName); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/FacebookActivity.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | import com.bumptech.glide.Glide; 13 | import com.facebook.CallbackManager; 14 | import com.facebook.FacebookCallback; 15 | import com.facebook.FacebookException; 16 | import com.facebook.FacebookSdk; 17 | import com.facebook.GraphRequest; 18 | import com.facebook.GraphResponse; 19 | import com.facebook.Profile; 20 | import com.facebook.login.LoginBehavior; 21 | import com.facebook.login.LoginManager; 22 | import com.facebook.login.LoginResult; 23 | 24 | import org.json.JSONException; 25 | import org.json.JSONObject; 26 | 27 | import java.io.IOException; 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | import java.util.Locale; 31 | 32 | public class FacebookActivity extends AppCompatActivity { 33 | private static final String TAG = FacebookActivity.class.getSimpleName(); 34 | private ImageView mImgPhoto; 35 | private TextView mTextDescription; 36 | 37 | // FB 38 | private LoginManager loginManager; 39 | private CallbackManager callbackManager; 40 | 41 | @Override 42 | protected void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_facebook); 45 | 46 | // init facebook 47 | FacebookSdk.sdkInitialize(getApplicationContext()); 48 | // init LoginManager & CallbackManager 49 | loginManager = LoginManager.getInstance(); 50 | callbackManager = CallbackManager.Factory.create(); 51 | 52 | findViewById(R.id.mImgFBBut).setOnClickListener(new View.OnClickListener() { 53 | @Override 54 | public void onClick(View v) { 55 | // Facebook Login 56 | loginFB(); 57 | } 58 | }); 59 | findViewById(R.id.mImgLogoutBut).setOnClickListener(new View.OnClickListener() { 60 | @Override 61 | public void onClick(View v) { 62 | // Facebook Logout 63 | loginManager.logOut(); 64 | Glide.with(FacebookActivity.this) 65 | .load(R.drawable.ic_user_60dp) 66 | .crossFade() 67 | .into(mImgPhoto); 68 | mTextDescription.setText(""); 69 | } 70 | }); 71 | mImgPhoto = (ImageView) findViewById(R.id.mImgPhoto); 72 | mTextDescription = (TextView) findViewById(R.id.mTextDescription); 73 | 74 | // method_1.判斷用戶是否登入過 75 | if (Profile.getCurrentProfile() != null) { 76 | Profile profile = Profile.getCurrentProfile(); 77 | // 取得用戶大頭照 78 | Uri userPhoto = profile.getProfilePictureUri(300, 300); 79 | String id = profile.getId(); 80 | String name = profile.getName(); 81 | Log.d(TAG, "Facebook userPhoto: " + userPhoto); 82 | Log.d(TAG, "Facebook id: " + id); 83 | Log.d(TAG, "Facebook name: " + name); 84 | } 85 | 86 | // method_2.判斷用戶是否登入過 87 | /*if (AccessToken.getCurrentAccessToken() != null) { 88 | Log.d(TAG, "Facebook getApplicationId: " + AccessToken.getCurrentAccessToken().getApplicationId()); 89 | Log.d(TAG, "Facebook getUserId: " + AccessToken.getCurrentAccessToken().getUserId()); 90 | Log.d(TAG, "Facebook getExpires: " + AccessToken.getCurrentAccessToken().getExpires()); 91 | Log.d(TAG, "Facebook getLastRefresh: " + AccessToken.getCurrentAccessToken().getLastRefresh()); 92 | Log.d(TAG, "Facebook getToken: " + AccessToken.getCurrentAccessToken().getToken()); 93 | Log.d(TAG, "Facebook getSource: " + AccessToken.getCurrentAccessToken().getSource()); 94 | }*/ 95 | } 96 | 97 | private void loginFB() { 98 | // 設定FB login的顯示方式 ; 預設是:NATIVE_WITH_FALLBACK 99 | /** 100 | * 1. NATIVE_WITH_FALLBACK 101 | * 2. NATIVE_ONLY 102 | * 3. KATANA_ONLY 103 | * 4. WEB_ONLY 104 | * 5. WEB_VIEW_ONLY 105 | * 6. DEVICE_AUTH 106 | */ 107 | loginManager.setLoginBehavior(LoginBehavior.NATIVE_WITH_FALLBACK); 108 | // 設定要跟用戶取得的權限,以下3個是基本可以取得,不需要經過FB的審核 109 | List permissions = new ArrayList<>(); 110 | permissions.add("public_profile"); 111 | permissions.add("email"); 112 | permissions.add("user_friends"); 113 | // 設定要讀取的權限 114 | loginManager.logInWithReadPermissions(this, permissions); 115 | loginManager.registerCallback(callbackManager, new FacebookCallback() { 116 | @Override 117 | public void onSuccess(final LoginResult loginResult) { 118 | /** 119 | Facebook getApplicationId: 1263340450401125 120 | Facebook getUserId: 228579214326556 121 | Facebook getExpires: Sat Aug 12 11:55:25 GMT+08:00 2017 122 | Facebook getLastRefresh: Tue Jun 13 11:57:15 GMT+08:00 2017 123 | Facebook getToken: EAAR9AF7Gy2UBAEHvxir6gNDeozTFjL8JoQzoo9ZA2uxqDyi1lpexqVLFWNB6RpfLzh1SHveZBxzUGVY4ZAJR9TLGiCgwDW6ZAebq4NqgnckBc3ZCbE7ZA456CmTCeALp57wvTjPrr5O4KcUgRMrPalfVmwfoNlOFyIQtWZAZChOdhPT6XqNuCERRqyfmWSerKcWyeZCIXvi6U0zpm8H8pdOliqYR9qznesafLoIiLylLYqAZDZD 124 | Facebook getSource: FACEBOOK_APPLICATION_WEB 125 | Facebook getRecentlyGrantedPermissions: [public_profile, user_friends, email] 126 | Facebook getRecentlyDeniedPermissions: [] 127 | */ 128 | /*Log.d(TAG, "Facebook getApplicationId: " + loginResult.getAccessToken().getApplicationId()); 129 | Log.d(TAG, "Facebook getUserId: " + loginResult.getAccessToken().getUserId()); 130 | Log.d(TAG, "Facebook getExpires: " + loginResult.getAccessToken().getExpires()); 131 | Log.d(TAG, "Facebook getLastRefresh: " + loginResult.getAccessToken().getLastRefresh()); 132 | Log.d(TAG, "Facebook getToken: " + loginResult.getAccessToken().getToken()); 133 | Log.d(TAG, "Facebook getSource: " + loginResult.getAccessToken().getSource()); 134 | Log.d(TAG, "Facebook getRecentlyGrantedPermissions: " + loginResult.getRecentlyGrantedPermissions()); 135 | Log.d(TAG, "Facebook getRecentlyDeniedPermissions: " + loginResult.getRecentlyDeniedPermissions());*/ 136 | 137 | GraphRequest graphRequest = GraphRequest.newMeRequest(loginResult.getAccessToken(), new GraphRequest.GraphJSONObjectCallback() { 138 | @Override 139 | public void onCompleted(JSONObject object, GraphResponse response) { 140 | try { 141 | if (response.getConnection().getResponseCode() == 200) { 142 | Log.d(TAG, "Facebook JSONObject:" + object); 143 | long id = object.getLong("id"); 144 | String name = object.getString("name"); 145 | String email = object.getString("email"); 146 | Log.d(TAG, "Facebook id:" + id); 147 | Log.d(TAG, "Facebook name:" + name); 148 | Log.d(TAG, "Facebook email:" + email); 149 | // 取得用戶大頭照 150 | Profile profile = Profile.getCurrentProfile(); 151 | // 設定大頭照大小 152 | Uri userPhoto = profile.getProfilePictureUri(300, 300); 153 | Log.d(TAG, "Facebook userPhoto: " + userPhoto); 154 | Glide.with(FacebookActivity.this) 155 | .load(userPhoto.toString()) 156 | .crossFade() 157 | .into(mImgPhoto); 158 | mTextDescription.setText(String.format(Locale.TAIWAN, "Name:%s\nE-mail:%s", name, email)); 159 | } 160 | } catch (IOException e) { 161 | e.printStackTrace(); 162 | } catch (JSONException e) { 163 | e.printStackTrace(); 164 | } 165 | } 166 | }); 167 | // https://developers.facebook.com/docs/android/graph?locale=zh_TW 168 | // 如果要取得email,需透過添加參數的方式來獲取(如下) 169 | // 不添加只能取得id & name 170 | Bundle parameters = new Bundle(); 171 | parameters.putString("fields", "id,name,email"); 172 | graphRequest.setParameters(parameters); 173 | graphRequest.executeAsync(); 174 | } 175 | 176 | @Override 177 | public void onCancel() { 178 | Log.d(TAG, "Facebook onCancel"); 179 | } 180 | 181 | @Override 182 | public void onError(FacebookException error) { 183 | Log.d(TAG, "Facebook onError:" + error.toString()); 184 | } 185 | }); 186 | } 187 | 188 | @Override 189 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 190 | super.onActivityResult(requestCode, resultCode, data); 191 | callbackManager.onActivityResult(requestCode, resultCode, data); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/HandlerThreadActivity.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.BitmapFactory; 5 | import android.os.Handler; 6 | import android.os.HandlerThread; 7 | import android.os.Process; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.os.Bundle; 10 | import android.util.Log; 11 | import android.widget.ImageView; 12 | import android.widget.TextView; 13 | 14 | import java.io.ByteArrayOutputStream; 15 | import java.io.InputStream; 16 | import java.net.HttpURLConnection; 17 | import java.net.URL; 18 | 19 | public class HandlerThreadActivity extends AppCompatActivity { 20 | private static final String TAG = HandlerThreadActivity.class.getSimpleName(); 21 | 22 | private TextView mTextView; 23 | private ImageView mImgView; 24 | // HandlerThread & Hanlder 25 | private HandlerThread downloadThread; 26 | private Handler downloadHandler; 27 | // 是否要定時更新 28 | private boolean isUpdate = false; 29 | 30 | @Override 31 | protected void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | setContentView(R.layout.activity_handler_thread); 34 | 35 | mTextView = (TextView) findViewById(R.id.mTextView); 36 | mImgView = (ImageView) findViewById(R.id.mImgView); 37 | 38 | mTextView.setText("目前亂數:"); 39 | 40 | downloadThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND); 41 | // 別忘了要呼叫start()方法,否則在下面downloadThread.getLooper()取到的Looper會是null 42 | downloadThread.start(); 43 | downloadHandler = new Handler(downloadThread.getLooper()); 44 | // 分別打印Main Thread & downloadThread資訊 45 | Log.d(TAG, "Main Looper:" + getMainLooper() + " thread:" + getMainLooper().getThread() + 46 | " progress:" + Process.getThreadPriority((int) getMainLooper().getThread().getId())); 47 | Log.d(TAG, "Thread Looper:" + downloadThread.getLooper() + " thread:" + downloadThread + 48 | " progress:" + Process.getThreadPriority(downloadThread.getThreadId())); 49 | } 50 | 51 | // 用來產生亂數 52 | private Runnable mRunnableRandom = new Runnable() { 53 | @Override 54 | public void run() { 55 | runOnUiThread(new Runnable() { 56 | @Override 57 | public void run() { 58 | int random = (int) (Math.random() * 8999) + 1000; 59 | mTextView.setText("目前亂數:" + random); 60 | } 61 | }); 62 | if (isUpdate) { 63 | downloadHandler.postDelayed(mRunnableRandom, 1000); 64 | } 65 | } 66 | }; 67 | 68 | // 用來下載圖片 69 | private Runnable mRunnableImg = new Runnable() { 70 | @Override 71 | public void run() { 72 | try { 73 | URL url = new URL("http://www.fhm.com.tw/fhm_upload/images/Tzuyu_10.jpg"); 74 | HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); 75 | httpURLConnection.setConnectTimeout(15000); 76 | httpURLConnection.setReadTimeout(15000); 77 | httpURLConnection.setDoInput(true); 78 | httpURLConnection.setRequestMethod("GET"); 79 | InputStream is = null; 80 | ByteArrayOutputStream os = null; 81 | int responseCode = httpURLConnection.getResponseCode(); 82 | if (responseCode == 200) { 83 | is = httpURLConnection.getInputStream(); 84 | os = new ByteArrayOutputStream(); 85 | byte[] buffer = new byte[1024]; 86 | int len; 87 | while ((len = is.read(buffer)) != -1) { 88 | os.write(buffer, 0, len); 89 | } 90 | final Bitmap bitmap = BitmapFactory.decodeByteArray(os.toByteArray(), 0, os.toByteArray().length); 91 | runOnUiThread(new Runnable() { 92 | @Override 93 | public void run() { 94 | mImgView.setImageBitmap(bitmap); 95 | } 96 | }); 97 | } 98 | if (is != null) { 99 | os.flush(); 100 | os.close(); 101 | is.close(); 102 | } 103 | } catch (Exception e) { 104 | Log.d(TAG, "Exception:" + e.getMessage()); 105 | } 106 | } 107 | }; 108 | 109 | @Override 110 | protected void onResume() { 111 | super.onResume(); 112 | isUpdate = true; 113 | // 發送Runnable到downloadThread Looper對列裡 114 | downloadHandler.postDelayed(mRunnableRandom, 1000); 115 | downloadHandler.postDelayed(mRunnableImg, 2000); 116 | } 117 | 118 | @Override 119 | protected void onStop() { 120 | super.onStop(); 121 | isUpdate = false; 122 | // 移除Runnable 123 | downloadHandler.removeCallbacks(mRunnableRandom); 124 | downloadHandler.removeCallbacks(mRunnableImg); 125 | } 126 | 127 | @Override 128 | protected void onDestroy() { 129 | super.onDestroy(); 130 | // 將downloadThread停止所有的任務 131 | boolean isQuit; 132 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) { 133 | // 安全的停止所有的任務 134 | isQuit = downloadThread.quitSafely(); 135 | } else { 136 | // 強制中斷所有的任務 137 | isQuit = downloadThread.quit(); 138 | } 139 | Log.d(TAG, "isQuit:" + isQuit); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/LayoutActivity.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.os.Handler; 6 | import android.os.Message; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.Toolbar; 9 | import android.util.Log; 10 | import android.util.TypedValue; 11 | import android.view.ViewStub; 12 | import android.widget.ImageView; 13 | import android.widget.TextView; 14 | 15 | public class LayoutActivity extends AppCompatActivity { 16 | /** 17 | * 布局優化 : include、merge使用 18 | */ 19 | private static final String TAG = LayoutActivity.class.getSimpleName(); 20 | private ViewStub mViewStub; 21 | private ImageView mImgView; 22 | private Handler mHandler = new Handler() { 23 | @Override 24 | public void handleMessage(Message msg) { 25 | super.handleMessage(msg); 26 | switch (msg.what) { 27 | case 100: 28 | if (mImgView == null) mImgView = (ImageView) mViewStub.inflate(); 29 | Log.d(TAG, "mImgView already load. " + mImgView); 30 | break; 31 | } 32 | } 33 | }; 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.activity_layout); 39 | 40 | // 當include,有設定android:id時,直接用include的Id,來找到相對應的根 View 41 | // 而其裡面子View,直接透過findViewById()即可取得 42 | Toolbar mToolBar = (Toolbar) findViewById(R.id.mToolBarLayout); 43 | mToolBar.setTitle("Include ToolBar"); 44 | mToolBar.setTitleTextColor(Color.WHITE); 45 | TextView mTextView = (TextView) findViewById(R.id.mTextView); 46 | mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); 47 | 48 | // 當include,沒有設定android:id時,直接用findViewById來找到相對應的View 49 | /*Toolbar mToolBar = (Toolbar) findViewById(R.id.mToolBar); 50 | mToolBar.setTitle("Include ToolBar"); 51 | mToolBar.setTitleTextColor(Color.WHITE); 52 | TextView mTextView = (TextView) findViewById(R.id.mTextView); 53 | mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);*/ 54 | 55 | // 當include,有設定android:id時,直接用include的Id,來找到相對應的根 View 56 | // 此時的子View 可以透過這2個方式尋找 57 | /*View includeView = findViewById(R.id.mLinearLayout); 58 | // First 59 | TextView mTextHi = (TextView) includeView.findViewById(R.id.mTextHi); 60 | TextView mTextHello = (TextView) includeView.findViewById(R.id.mTextHello); 61 | includeView.setBackgroundColor(Color.LTGRAY);*/ 62 | // Second 63 | TextView mTextHi = (TextView) findViewById(R.id.mTextHi); 64 | TextView mTextHello = (TextView) findViewById(R.id.mTextHello); 65 | mTextHi.setText("Hi"); 66 | mTextHello.setText("Hello"); 67 | 68 | // 判斷ViewStub是否已加載 方式_1 use setVisibility() 69 | // 該方式無法取得到View,單純用來顯示 70 | /*mViewStub = (ViewStub) findViewById(R.id.mViewStub); 71 | mViewStub.setVisibility(View.VISIBLE); 72 | if (mViewStub.getVisibility() == View.VISIBLE) { 73 | // 已經載入 74 | Log.d(TAG, "mImgView already load. " + mImgView); 75 | } else { 76 | // 尚未載入 77 | Log.d(TAG, "mImgView not load. " + mImgView); 78 | }*/ 79 | 80 | // 判斷ViewStub是否已加載 方式_2 use Object is null 81 | mViewStub = (ViewStub) findViewById(R.id.mViewStub); 82 | /*if (mImgView == null) { 83 | // 直接取得ImageView,並載入 84 | mImgView = (ImageView) mViewStub.inflate(); 85 | Log.d(TAG, "mImgView not load. " + mImgView); 86 | } else { 87 | Log.d(TAG, "mImgView already load."); 88 | }*/ 89 | 90 | // 模擬延遲5秒 在載入 91 | Message message = Message.obtain(); 92 | message.what = 100; 93 | mHandler.sendMessageDelayed(message, 5000); 94 | } 95 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign; 2 | 3 | import android.content.Intent; 4 | import android.content.res.Configuration; 5 | import android.graphics.Color; 6 | import android.os.Bundle; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.support.v7.widget.Toolbar; 9 | import android.view.MenuItem; 10 | import android.view.View; 11 | import android.widget.Toast; 12 | 13 | import com.rayzhang.android.materialdesign.intentservice.IntentServiceActivity; 14 | import com.rayzhang.android.materialdesign.itemhelper.ItemTouchHelperActivity; 15 | import com.rayzhang.android.materialdesign.onboarding.OnboardingActivity; 16 | 17 | public class MainActivity extends AppCompatActivity { 18 | private static final String TAG = MainActivity.class.getSimpleName() + "Ray"; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.activity_main); 24 | 25 | String name = ""; 26 | // 回覆數據 27 | if (savedInstanceState != null) { 28 | name = savedInstanceState.getString("Name"); 29 | } 30 | logStr("onCreate:" + name); 31 | 32 | Toolbar mToolBar = (Toolbar) findViewById(R.id.mToolBar); 33 | // 設定導航攔的圖示 34 | mToolBar.setNavigationIcon(R.drawable.ic_google_play_24dp); 35 | // 設定toolBar的logo 36 | mToolBar.setLogo(R.drawable.ic_arrow_back_white_24dp); 37 | // 設定標題文字 38 | mToolBar.setTitle("Title"); 39 | // 設定標題文字顏色 40 | mToolBar.setTitleTextColor(Color.YELLOW); 41 | // 設定子標題文字 42 | mToolBar.setSubtitle("Subtitle"); 43 | // 設定子標題文字顏色 44 | mToolBar.setSubtitleTextColor(Color.GREEN); 45 | // 設定toolBar的actionMenu 46 | mToolBar.inflateMenu(R.menu.toolbar_menu); 47 | // 設定actionMenu的點擊事件 48 | mToolBar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { 49 | @Override 50 | public boolean onMenuItemClick(MenuItem item) { 51 | switch (item.getItemId()) { 52 | case R.id.favorite: 53 | Toast.makeText(MainActivity.this, "favorite", Toast.LENGTH_SHORT).show(); 54 | break; 55 | case R.id.delete: 56 | Toast.makeText(MainActivity.this, "favorite", Toast.LENGTH_SHORT).show(); 57 | break; 58 | case R.id.action_item1: 59 | startActivity(new Intent(MainActivity.this, ItemTouchHelperActivity.class)); 60 | break; 61 | case R.id.action_item2: 62 | startActivity(new Intent(MainActivity.this, DialogActivity.class)); 63 | break; 64 | case R.id.action_item3: 65 | startActivity(new Intent(MainActivity.this, OnboardingActivity.class)); 66 | break; 67 | case R.id.action_item4: 68 | startActivity(new Intent(MainActivity.this, AsyncTaskActivity.class)); 69 | break; 70 | case R.id.action_item5: 71 | startActivity(new Intent(MainActivity.this, IntentServiceActivity.class)); 72 | break; 73 | case R.id.action_item6: 74 | startActivity(new Intent(MainActivity.this, HandlerThreadActivity.class)); 75 | case R.id.action_item7: 76 | startActivity(new Intent(MainActivity.this, ExecutorActivity.class)); 77 | break; 78 | case R.id.action_item8: 79 | startActivity(new Intent(MainActivity.this, CompressActivity.class)); 80 | break; 81 | } 82 | return true; 83 | } 84 | }); 85 | 86 | findViewById(R.id.mCardView).setOnClickListener(new View.OnClickListener() { 87 | @Override 88 | public void onClick(View v) { 89 | // Collapsing 90 | Intent i = new Intent(MainActivity.this, CollapsingActivity.class); 91 | //i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 92 | //i.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 93 | //i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 94 | //i.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); 95 | startActivity(i); 96 | } 97 | }); 98 | findViewById(R.id.mFabBut).setOnClickListener(new View.OnClickListener() { 99 | @Override 100 | public void onClick(View view) { 101 | // facebook login 102 | startActivity(new Intent(MainActivity.this, FacebookActivity.class)); 103 | } 104 | }); 105 | 106 | /*final ImageView mImgView = (ImageView) findViewById(R.id.mImgView); 107 | Rect localImgRect = new Rect(); 108 | // 取得View,相對於Parent View的位置 109 | mImgView.getLocalVisibleRect(localImgRect); 110 | Log.d(TAG, "Image getLocalVisibleRect:" + localImgRect); 111 | 112 | // 取得View在整個螢幕上的位置 113 | Rect globaImgRect = new Rect(); 114 | mImgView.getGlobalVisibleRect(globaImgRect); 115 | Log.d(TAG, "Image getGlobalVisibleRect:" + globaImgRect); 116 | 117 | // 取得X、Y軸(但是相對於Parent View) 118 | Log.d(TAG, String.format(Locale.TAIWAN, "Image x:%.2f y:%.2f", mImgView.getX(), mImgView.getY())); 119 | 120 | // 取得當前Activity的Window大小(DecorView) 121 | Rect windowRect = new Rect(); 122 | mCardView.getWindowVisibleDisplayFrame(windowRect); 123 | Log.d(TAG, "getWindowVisibleDisplayFrame:" + windowRect); 124 | 125 | // 在屏幕上計算此View的坐標。 參數必須是兩個整數的數組。 該方法返回後,該數組包含該順序中的x和y位置。 126 | int[] outLocationWindows = new int[2]; 127 | mCardView.getLocationInWindow(outLocationWindows); 128 | for (int i = 0, j = outLocationWindows.length; i < j; i++) { 129 | Log.d(TAG, "CardView getLocationInWindow:" + outLocationWindows[i]); 130 | } 131 | // 在其窗口中計算此View的坐標。 參數必須是兩個整數的數組。 該方法返回後,該數組包含該順序中的x和y位置。 132 | int[] outLocationScreen = new int[2]; 133 | mCardView.getLocationOnScreen(outLocationScreen); 134 | for (int i = 0, j = outLocationWindows.length; i < j; i++) { 135 | Log.d(TAG, "CardView outLocationScreen:" + outLocationScreen[i]); 136 | }*/ 137 | } 138 | 139 | private void logStr(String str) { 140 | //Log.d(TAG, str); 141 | } 142 | 143 | @Override 144 | protected void onSaveInstanceState(Bundle outState) { 145 | super.onSaveInstanceState(outState); 146 | logStr("onSaveInstanceState"); 147 | outState.putString("Name", "Ray"); 148 | } 149 | 150 | @Override 151 | protected void onRestoreInstanceState(Bundle savedInstanceState) { 152 | super.onRestoreInstanceState(savedInstanceState); 153 | // 螢幕翻轉時 會觸發 154 | // 這邊的Bundle 不用判斷是否為null 因為一定會有值 155 | logStr("onRestoreInstanceState"); 156 | } 157 | 158 | @Override 159 | public void onConfigurationChanged(Configuration newConfig) { 160 | super.onConfigurationChanged(newConfig); 161 | // 將Activity設定如下(在AndroidManifest.xml) 會觸發 162 | // android:configChanges="orientation|keyboardHidden|screenSize" 163 | logStr("onConfigurationChanged"); 164 | } 165 | 166 | @Override 167 | protected void onPause() { 168 | super.onPause(); 169 | logStr("onPause"); 170 | } 171 | 172 | @Override 173 | protected void onRestart() { 174 | super.onRestart(); 175 | logStr("onRestart"); 176 | } 177 | 178 | @Override 179 | protected void onResume() { 180 | super.onResume(); 181 | logStr("onResume"); 182 | } 183 | 184 | @Override 185 | protected void onStart() { 186 | super.onStart(); 187 | logStr("onStart"); 188 | } 189 | 190 | @Override 191 | protected void onStop() { 192 | super.onStop(); 193 | logStr("onStop"); 194 | } 195 | 196 | @Override 197 | protected void onDestroy() { 198 | super.onDestroy(); 199 | logStr("onDestroy"); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/adapter/DemoAdapter.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign.adapter; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import com.rayzhang.android.materialdesign.R; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * Created by Ray on 2017/3/12. 16 | */ 17 | 18 | public class DemoAdapter extends RecyclerView.Adapter { 19 | private static final int NORMAL_ITEM = 9999; 20 | private ArrayList list; 21 | 22 | public DemoAdapter(List list) { 23 | this.list = new ArrayList<>(); 24 | this.list.addAll(list); 25 | } 26 | 27 | @Override 28 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 29 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_item, parent, false); 30 | return new DemoNView(view); 31 | } 32 | 33 | @Override 34 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 35 | int viewType = getItemViewType(position); 36 | if (viewType == NORMAL_ITEM) { 37 | ((DemoNView) holder).mTextView.setText(list.get(position)); 38 | if (onItemClickListener != null) { 39 | ((DemoNView) holder).mTextView.setOnClickListener(new View.OnClickListener() { 40 | @Override 41 | public void onClick(View v) { 42 | onItemClickListener.onItemClick(v); 43 | } 44 | }); 45 | } 46 | } 47 | } 48 | 49 | @Override 50 | public int getItemCount() { 51 | return list.size(); 52 | } 53 | 54 | @Override 55 | public int getItemViewType(int position) { 56 | return NORMAL_ITEM; 57 | } 58 | 59 | public class DemoNView extends RecyclerView.ViewHolder { 60 | private TextView mTextView; 61 | 62 | public DemoNView(View itemView) { 63 | super(itemView); 64 | mTextView = (TextView) itemView.findViewById(R.id.mTextView); 65 | } 66 | } 67 | 68 | public interface onItemClickListener { 69 | void onItemClick(View view); 70 | } 71 | 72 | private onItemClickListener onItemClickListener; 73 | 74 | public void setOnItemClickListener(onItemClickListener onItemClickListener) { 75 | this.onItemClickListener = onItemClickListener; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/adapter/itemdecoration/LinearSectionDecoration.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign.adapter.itemdecoration; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Color; 5 | import android.graphics.Paint; 6 | import android.graphics.Rect; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.View; 10 | 11 | /** 12 | * Created by Ray on 2017/6/11. 13 | */ 14 | 15 | public class LinearSectionDecoration extends RecyclerView.ItemDecoration { 16 | private static final String TAG = LinearSectionDecoration.class.getSimpleName(); 17 | // 分類群組的大小 18 | private int sectionSize = 30; 19 | // 分隔線的大小 20 | private int dividerSize = 1; 21 | // 是否要有分類群組 22 | private boolean hasSection = false; 23 | private Paint mPaint, mPaintText; 24 | private LinearSectionCallback callback; 25 | 26 | public LinearSectionDecoration(int dividerSize, int dividerColor) { 27 | this.dividerSize = dividerSize; 28 | initPaint(dividerColor); 29 | } 30 | 31 | public LinearSectionDecoration(int sectionSize, int dividerSize, int dividerColor, LinearSectionCallback callback) { 32 | this.sectionSize = sectionSize; 33 | this.dividerSize = dividerSize; 34 | this.callback = callback; 35 | hasSection = true; 36 | // 繪製標題名稱的paint 37 | mPaintText = new Paint(Paint.ANTI_ALIAS_FLAG); 38 | mPaintText.setColor(Color.argb(255, 255, 255, 255)); 39 | mPaintText.setTextSize(16f); 40 | mPaintText.setDither(true); 41 | initPaint(dividerColor); 42 | } 43 | 44 | private void initPaint(int color) { 45 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 46 | mPaint.setColor(color); 47 | mPaint.setStyle(Paint.Style.FILL); 48 | mPaint.setDither(true); 49 | } 50 | 51 | /** 52 | * 律定每個Item偏移的距離 53 | * 54 | * @param outRect 55 | * @param view 56 | * @param parent 57 | * @param state 58 | */ 59 | @Override 60 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 61 | super.getItemOffsets(outRect, view, parent, state); 62 | 63 | int position = parent.getChildAdapterPosition(view); 64 | RecyclerView.LayoutManager manager = parent.getLayoutManager(); 65 | if (manager instanceof LinearLayoutManager) { 66 | if (((LinearLayoutManager) manager).getOrientation() == LinearLayoutManager.VERTICAL) { 67 | if (hasSection) { 68 | // 如果要繪製分類群組 69 | setVerticalItemOffSetBySection(outRect, position); 70 | } else { 71 | setVerticalItemOffSet(outRect, position); 72 | } 73 | } 74 | } 75 | } 76 | 77 | private void setVerticalItemOffSetBySection(Rect outRect, int position) { 78 | if (isFirstInGroup(position)) { 79 | outRect.set(0, sectionSize, 0, 0); 80 | } else { 81 | outRect.set(0, dividerSize, 0, 0); 82 | } 83 | } 84 | 85 | private void setVerticalItemOffSet(Rect outRect, int position) { 86 | if (position != 0) outRect.set(0, dividerSize, 0, 0); 87 | } 88 | 89 | private boolean isFirstInGroup(int position) { 90 | // 判斷是否為相同群組的第1個 91 | return position == 0 || !callback.getItemStr(position).equals(callback.getItemStr(position - 1)); 92 | } 93 | 94 | /** 95 | * 繪製分隔線 96 | * 97 | * @param c 98 | * @param parent 99 | * @param state 100 | */ 101 | @Override 102 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 103 | super.onDraw(c, parent, state); 104 | 105 | RecyclerView.LayoutManager manager = parent.getLayoutManager(); 106 | if (manager instanceof LinearLayoutManager) { 107 | if (((LinearLayoutManager) manager).getOrientation() == LinearLayoutManager.VERTICAL) { 108 | if (hasSection) { 109 | drawVerticalBySection(c, parent); 110 | } else { 111 | drawVertical(c, parent); 112 | } 113 | } 114 | } 115 | } 116 | 117 | private void drawVerticalBySection(Canvas c, RecyclerView parent) { 118 | int childCount = parent.getChildCount(); 119 | int left = parent.getPaddingLeft(); 120 | int right = parent.getWidth() - parent.getPaddingRight(); 121 | 122 | for (int i = 0; i < childCount; i++) { 123 | View child = parent.getChildAt(i); 124 | RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); 125 | int position = parent.getChildAdapterPosition(child); 126 | 127 | int top = child.getTop() + params.topMargin; 128 | int bottom = top + dividerSize; 129 | if (isFirstInGroup(position)) { 130 | // 要減去sectionSize的大小 131 | top = child.getTop() - sectionSize + params.topMargin; 132 | bottom = top + sectionSize; 133 | } 134 | c.drawRect(left, top, right, bottom, mPaint); 135 | if (hasSection && isFirstInGroup(position)) { 136 | // 繪製標題名稱 137 | c.drawText(callback.getItemStr(position), 20, bottom - sectionSize / 3, mPaintText); 138 | } 139 | } 140 | } 141 | 142 | private void drawVertical(Canvas c, RecyclerView parent) { 143 | int childCount = parent.getChildCount(); 144 | int left = parent.getPaddingLeft(); 145 | int right = parent.getWidth() - parent.getPaddingRight(); 146 | 147 | for (int i = 0; i < childCount; i++) { 148 | View child = parent.getChildAt(i); 149 | RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); 150 | int position = parent.getChildAdapterPosition(child); 151 | 152 | if (position != 0) { 153 | int top = child.getTop() + params.topMargin; 154 | int bottom = top + dividerSize; 155 | c.drawRect(left, top, right, bottom, mPaint); 156 | } 157 | } 158 | } 159 | 160 | /** 161 | * 繪製分隔線,會繪製在View上方 162 | * 163 | * @param c 164 | * @param parent 165 | * @param state 166 | */ 167 | // TODO : 標題分類 168 | @Override 169 | public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { 170 | super.onDrawOver(c, parent, state); 171 | 172 | // 如果沒有要繪製分類群組,就不繼續執行 173 | if (!hasSection) return; 174 | 175 | int childCount = parent.getChildCount(); 176 | int itemCount = parent.getAdapter().getItemCount(); 177 | int left = parent.getPaddingLeft(); 178 | int right = parent.getWidth() - parent.getPaddingRight(); 179 | 180 | // 上個Item分組的標誌 181 | String preGroupId = ""; 182 | // 現在Item分組的標誌 183 | String nowGroupId = "-1"; 184 | 185 | for (int i = 0; i < childCount; i++) { 186 | View child = parent.getChildAt(i); 187 | RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); 188 | int position = parent.getChildAdapterPosition(child); 189 | 190 | preGroupId = nowGroupId; 191 | nowGroupId = callback.getItemStr(position); 192 | // 如果目前的Item分組的標誌等於 "-1" or 跟前1個Item一樣,就跳過 193 | if (nowGroupId.equals("-1") || nowGroupId.equals(preGroupId)) continue; 194 | 195 | int otherSize = params.topMargin + parent.getPaddingTop(); 196 | int childBottom = child.getBottom(); 197 | 198 | int top = Math.max(otherSize + sectionSize, otherSize + child.getTop()); 199 | //Log.d(TAG, String.format(Locale.TAIWAN, "position:%d sectionSize:%d getTop():%d", position, sectionSize, child.getTop())); 200 | if (position + 1 < itemCount) { 201 | if (isLastInGroup(position) && childBottom < top) { 202 | // 如果是當前群組,最後1個Item並且 childBottom < top 203 | // 就把繪製製的top等於目前的childBottom,這樣才會達到吸附的效果 204 | top = childBottom; 205 | //Log.d(TAG, String.format(Locale.TAIWAN, "childBottom:%d", childBottom)); 206 | } 207 | } 208 | c.drawRect(left, top - sectionSize, right, top, mPaint); 209 | // 繪製標題名稱 210 | c.drawText(callback.getItemStr(position), 20, top - sectionSize / 3, mPaintText); 211 | } 212 | } 213 | 214 | private boolean isLastInGroup(int position) { 215 | // 判斷是否為當前群組的最後1個 216 | return !callback.getItemStr(position).equals(callback.getItemStr(position + 1)); 217 | } 218 | 219 | /** 220 | * 給外部調用的Callback,取得每個Item的字 221 | */ 222 | public interface LinearSectionCallback { 223 | // 取得當前位置Item的Text 224 | String getItemStr(int poisition); 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/dialog/MySelfDialog.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign.dialog; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.DialogFragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.Button; 11 | import android.widget.TextView; 12 | 13 | import com.rayzhang.android.materialdesign.R; 14 | 15 | /** 16 | * Created by Ray on 2017/4/16. 17 | */ 18 | 19 | public class MySelfDialog extends DialogFragment { 20 | /** 21 | * Use DialogFragment but view by myself. 22 | */ 23 | 24 | private static MySelfDialog dialog; 25 | private TextView mTextTitle, mTextMsg; 26 | private Button mButOK, mButCancel; 27 | private MySelfDialogListener listener; 28 | 29 | public static MySelfDialog instance(String title) { 30 | if (dialog == null) { 31 | synchronized (MySelfDialog.class) { 32 | if (dialog == null) { 33 | dialog = new MySelfDialog(); 34 | } 35 | } 36 | } 37 | Bundle bundle = new Bundle(); 38 | bundle.putString("title", title); 39 | dialog.setArguments(bundle); 40 | return dialog; 41 | } 42 | 43 | @Override 44 | public void onCreate(@Nullable Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | // android.R.style.Theme_Holo_Light_Dialog 47 | setStyle(DialogFragment.STYLE_NORMAL, R.style.MyDialogTheme); 48 | //setStyle(DialogFragment.STYLE_NO_FRAME, R.style.MyDialogTheme); 49 | //setStyle(DialogFragment.STYLE_NO_INPUT, R.style.MyDialogTheme); 50 | //setStyle(DialogFragment.STYLE_NO_TITLE, R.style.MyDialogTheme); 51 | } 52 | 53 | @Nullable 54 | @Override 55 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 56 | String title = getArguments().getString("title"); 57 | View view = inflater.inflate(R.layout.dialog_myself, container, false); 58 | mTextTitle = (TextView) view.findViewById(R.id.mTextTitle); 59 | mTextMsg = (TextView) view.findViewById(R.id.mTextMsg); 60 | mButOK = (Button) view.findViewById(R.id.mButOK); 61 | mButCancel = (Button) view.findViewById(R.id.mButCancel); 62 | 63 | mTextTitle.setText(title); 64 | mTextMsg.setText("是否要離開此頁面MySelfDialog"); 65 | 66 | mButOK.setOnClickListener(new View.OnClickListener() { 67 | @Override 68 | public void onClick(View v) { 69 | if (listener != null) { 70 | listener.onDialogOKClick(MySelfDialog.this); 71 | } 72 | } 73 | }); 74 | mButCancel.setOnClickListener(new View.OnClickListener() { 75 | @Override 76 | public void onClick(View v) { 77 | if (listener != null) { 78 | listener.onDialogCancelClick(MySelfDialog.this); 79 | } 80 | } 81 | }); 82 | return view; 83 | } 84 | 85 | @Override 86 | public void onAttach(Context context) { 87 | super.onAttach(context); 88 | try { 89 | listener = (MySelfDialogListener) context; 90 | } catch (ClassCastException e) { 91 | throw new ClassCastException(context.toString() + " must implement NoticeDialogListener"); 92 | } 93 | } 94 | 95 | public interface MySelfDialogListener { 96 | void onDialogOKClick(DialogFragment dialog); 97 | 98 | void onDialogCancelClick(DialogFragment dialog); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/dialog/NoticeDialog.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign.dialog; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.os.Bundle; 7 | import android.support.annotation.NonNull; 8 | import android.support.v4.app.DialogFragment; 9 | import android.support.v7.app.AlertDialog; 10 | 11 | import com.rayzhang.android.materialdesign.R; 12 | 13 | /** 14 | * Created by Ray on 2017/4/16. 15 | */ 16 | 17 | public class NoticeDialog extends DialogFragment { 18 | /** 19 | * Use DialogFragment 20 | */ 21 | private static NoticeDialog dialog; 22 | private NoticeDialogListener listener; 23 | 24 | public static NoticeDialog instance(String title) { 25 | // 使用Singleton 26 | if (dialog == null) { 27 | synchronized (NoticeDialog.class) { 28 | if (dialog == null) { 29 | dialog = new NoticeDialog(); 30 | } 31 | } 32 | } 33 | // 傳入title參數 34 | Bundle bundle = new Bundle(); 35 | bundle.putString("title", title); 36 | dialog.setArguments(bundle); 37 | return dialog; 38 | } 39 | 40 | @NonNull 41 | @Override 42 | public Dialog onCreateDialog(Bundle savedInstanceState) { 43 | String title = getArguments().getString("title"); 44 | return new AlertDialog.Builder(getActivity()) 45 | .setTitle(title) 46 | .setMessage("是否要離開NoticeDialog") 47 | .setIcon(R.drawable.ic_bird_shape) 48 | .setPositiveButton("離開", new DialogInterface.OnClickListener() { 49 | @Override 50 | public void onClick(DialogInterface dialog, int which) { 51 | if (listener != null) { 52 | listener.onDialogPositiveClick(NoticeDialog.this); 53 | } 54 | } 55 | }) 56 | .setNegativeButton("等會兒", new DialogInterface.OnClickListener() { 57 | @Override 58 | public void onClick(DialogInterface dialog, int which) { 59 | if (listener != null) { 60 | listener.onDialogNegativeClick(NoticeDialog.this); 61 | } 62 | } 63 | }).create(); 64 | } 65 | 66 | @Override 67 | public void onAttach(Context context) { 68 | super.onAttach(context); 69 | try { 70 | // Instantiate the NoticeDialogListener so we can send events to the host 71 | listener = (NoticeDialogListener) context; 72 | } catch (ClassCastException e) { 73 | // The activity doesn't implement the interface, throw exception 74 | throw new ClassCastException(context.toString() + " must implement NoticeDialogListener"); 75 | } 76 | } 77 | 78 | public interface NoticeDialogListener { 79 | // 建立Listener 給外部呼叫的方法 80 | void onDialogPositiveClick(DialogFragment dialog); 81 | 82 | void onDialogNegativeClick(DialogFragment dialog); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/intentservice/DownloadIntentService.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign.intentservice; 2 | 3 | import android.app.IntentService; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.support.annotation.Nullable; 8 | import android.util.Log; 9 | 10 | import java.io.ByteArrayOutputStream; 11 | import java.io.InputStream; 12 | import java.net.HttpURLConnection; 13 | import java.net.URL; 14 | 15 | /** 16 | * Created by Ray on 2017/8/4. 17 | */ 18 | 19 | public class DownloadIntentService extends IntentService { 20 | private static final String TAG = DownloadIntentService.class.getSimpleName(); 21 | 22 | /** 23 | * Creates an IntentService. Invoked by your subclass's constructor. 24 | * 25 | * @param name Used to name the worker thread, important only for debugging. 26 | */ 27 | public DownloadIntentService(String name) { 28 | super(name); 29 | } 30 | 31 | public DownloadIntentService() { 32 | super(TAG); 33 | } 34 | 35 | @Override 36 | public void onCreate() { 37 | super.onCreate(); 38 | Log.d(TAG, "onCreate"); 39 | } 40 | 41 | @Override 42 | public int onStartCommand(@Nullable Intent intent, int flags, int startId) { 43 | Log.d(TAG, "onStartCommand"); 44 | return super.onStartCommand(intent, flags, startId); 45 | } 46 | 47 | @Override 48 | public void onStart(@Nullable Intent intent, int startId) { 49 | Log.d(TAG, "onStart"); 50 | super.onStart(intent, startId); 51 | } 52 | 53 | @Override 54 | protected void onHandleIntent(@Nullable Intent intent) { 55 | boolean isMainThread = Thread.currentThread() == getMainLooper().getThread(); 56 | // 確認是否開啟一個執行緒執行任務 57 | Log.d(TAG, "isMainThread :" + isMainThread); 58 | // 接收傳進來的intent資料 59 | Log.d(TAG, "onHandleIntent path:" + intent.getStringExtra("PATH")); 60 | try { 61 | // 睡眠2秒(模擬耗時任務) 62 | Thread.sleep(2000); 63 | // 下載圖片 64 | downloadPicture(intent.getStringExtra("PATH")); 65 | } catch (InterruptedException e) { 66 | e.printStackTrace(); 67 | } 68 | } 69 | 70 | private void downloadPicture(String path) { 71 | try { 72 | URL url = new URL(path); 73 | HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); 74 | httpURLConnection.setConnectTimeout(15000); 75 | httpURLConnection.setReadTimeout(15000); 76 | httpURLConnection.setDoInput(true); 77 | httpURLConnection.setRequestMethod("GET"); 78 | InputStream is = null; 79 | ByteArrayOutputStream os = null; 80 | int responseCode = httpURLConnection.getResponseCode(); 81 | if (responseCode == 200) { 82 | is = httpURLConnection.getInputStream(); 83 | os = new ByteArrayOutputStream(); 84 | byte[] buffer = new byte[1024]; 85 | int len; 86 | while ((len = is.read(buffer)) != -1) { 87 | os.write(buffer, 0, len); 88 | } 89 | Bitmap bitmap = BitmapFactory.decodeByteArray(os.toByteArray(), 0, os.toByteArray().length); 90 | Log.d(TAG, "savePicture bitmap:" + bitmap); 91 | } 92 | if (is != null) { 93 | os.flush(); 94 | os.close(); 95 | is.close(); 96 | } 97 | } catch (Exception e) { 98 | Log.d(TAG, "Exception:" + e.getMessage()); 99 | } 100 | } 101 | 102 | @Override 103 | public void onDestroy() { 104 | super.onDestroy(); 105 | Log.d(TAG, "onDestroy"); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/intentservice/IntentServiceActivity.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign.intentservice; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.util.Log; 7 | import android.view.View; 8 | import android.widget.Button; 9 | 10 | import com.rayzhang.android.materialdesign.R; 11 | 12 | public class IntentServiceActivity extends AppCompatActivity implements View.OnClickListener { 13 | private static final String TAG = IntentServiceActivity.class.getSimpleName(); 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_intent_service); 19 | Log.d("DownloadIntentService", "IntentServiceActivity onCreate"); 20 | 21 | Button mDownloadBut = (Button) findViewById(R.id.mDownloadBut); 22 | mDownloadBut.setOnClickListener(this); 23 | } 24 | 25 | @Override 26 | public void onClick(View v) { 27 | switch (v.getId()) { 28 | case R.id.mDownloadBut: 29 | Intent downloadService = new Intent(this, DownloadIntentService.class); 30 | downloadService.putExtra("PATH", "http://attach.setn.com/newsimages/2016/04/13/496395.jpg"); 31 | startService(downloadService); 32 | break; 33 | } 34 | } 35 | 36 | @Override 37 | protected void onResume() { 38 | super.onResume(); 39 | } 40 | 41 | @Override 42 | protected void onStop() { 43 | super.onStop(); 44 | } 45 | 46 | @Override 47 | protected void onDestroy() { 48 | super.onDestroy(); 49 | Log.d("DownloadIntentService", "IntentServiceActivity onDestroy"); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/itemhelper/ItemMoveSwipeListener.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign.itemhelper; 2 | 3 | /** 4 | * Created by Ray on 2017/7/8. 5 | */ 6 | 7 | public interface ItemMoveSwipeListener { 8 | /** 9 | * 設置1個監聽的interface 10 | * 11 | * onItemMove : 當item移動完的時候 12 | * onItemSwipe : 當item滑動完的時候 13 | */ 14 | boolean onItemMove(int fromPosition, int toPosition); 15 | 16 | void onItemSwipe(int position); 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/itemhelper/ItemTouchHelperActivity.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign.itemhelper; 2 | 3 | import android.graphics.Color; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.widget.DefaultItemAnimator; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.support.v7.widget.helper.ItemTouchHelper; 10 | 11 | import com.rayzhang.android.materialdesign.R; 12 | import com.rayzhang.android.materialdesign.adapter.itemdecoration.LinearSectionDecoration; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | public class ItemTouchHelperActivity extends AppCompatActivity { 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_item_touch_helper); 23 | 24 | RecyclerView mRecyView = (RecyclerView) findViewById(R.id.mRecyView); 25 | mRecyView.setHasFixedSize(true); 26 | mRecyView.setItemAnimator(new DefaultItemAnimator()); 27 | mRecyView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); 28 | mRecyView.addItemDecoration(new LinearSectionDecoration(1, Color.LTGRAY)); 29 | 30 | // 資料源 31 | final List list = new ArrayList<>(); 32 | for (int i = 1, j = 100; i <= j; i++) { 33 | list.add("" + i); 34 | } 35 | ItemTouchHelperAdapter adapter = new ItemTouchHelperAdapter(list); 36 | mRecyView.setAdapter(adapter); 37 | 38 | // 設置ItemTouchHelper並與RecycleView做關聯 39 | ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new RZItemTouchHelperCallback(adapter)); 40 | itemTouchHelper.attachToRecyclerView(mRecyView); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/itemhelper/ItemTouchHelperAdapter.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign.itemhelper; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import com.rayzhang.android.materialdesign.R; 10 | 11 | import java.util.Collections; 12 | import java.util.List; 13 | 14 | /** 15 | * Created by Ray on 2017/7/8. 16 | */ 17 | 18 | public class ItemTouchHelperAdapter extends RecyclerView.Adapter implements ItemMoveSwipeListener { 19 | private static final int NORMAL_ITEM = 9999; 20 | private List list; 21 | 22 | public ItemTouchHelperAdapter(List list) { 23 | this.list = list; 24 | } 25 | 26 | @Override 27 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 28 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_item, parent, false); 29 | return new ItemTouchHelperAdapter.DemoNView(view); 30 | } 31 | 32 | @Override 33 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 34 | int viewType = getItemViewType(position); 35 | if (viewType == NORMAL_ITEM) { 36 | ((ItemTouchHelperAdapter.DemoNView) holder).mTextView.setText(list.get(position)); 37 | } 38 | } 39 | 40 | @Override 41 | public int getItemCount() { 42 | return list.size(); 43 | } 44 | 45 | @Override 46 | public int getItemViewType(int position) { 47 | return NORMAL_ITEM; 48 | } 49 | 50 | private class DemoNView extends RecyclerView.ViewHolder { 51 | private TextView mTextView; 52 | 53 | private DemoNView(View itemView) { 54 | super(itemView); 55 | mTextView = (TextView) itemView.findViewById(R.id.mTextView); 56 | } 57 | } 58 | 59 | @Override 60 | public boolean onItemMove(int fromPosition, int toPosition) { 61 | // Collections.swap() 該方法是用來交換位置 62 | if (fromPosition >= 49) { 63 | // 當手指正在移動的item,它的位置 >= 50 就執行移動的動作 64 | // 但是移動的範圍一樣不能 < 50,否則這次移動不會執行 65 | Collections.swap(list, fromPosition, toPosition); 66 | notifyItemMoved(fromPosition, toPosition); 67 | return true; 68 | } 69 | // 如果不是,就不執行移動 70 | return false; 71 | } 72 | 73 | @Override 74 | public void onItemSwipe(int position) { 75 | list.remove(position); 76 | notifyItemRemoved(position); 77 | } 78 | } -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/itemhelper/RZItemTouchHelperCallback.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign.itemhelper; 2 | 3 | import android.graphics.Canvas; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.support.v7.widget.helper.ItemTouchHelper; 6 | 7 | /** 8 | * Created by Ray on 2017/7/8. 9 | *

10 | * Create a class and extends ItemTouchHelper.Callback 11 | */ 12 | 13 | public class RZItemTouchHelperCallback extends ItemTouchHelper.Callback { 14 | 15 | private ItemMoveSwipeListener itemMoveSwipeListener; 16 | 17 | public RZItemTouchHelperCallback(ItemMoveSwipeListener itemMoveSwipeListener) { 18 | this.itemMoveSwipeListener = itemMoveSwipeListener; 19 | } 20 | 21 | /** 22 | * 這個方法決定RecyclerView Item可以移動&滑動的方向 23 | * 24 | * @param recyclerView 25 | * @param viewHolder 26 | * @return 27 | */ 28 | @Override 29 | public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { 30 | 31 | // 先律定可「移動」的方向,這邊限制只能上、下移動 32 | int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN; 33 | 34 | // 在律定可「滑動」的方向,這邊限制只能左、右滑動 35 | int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; 36 | 37 | // 如果是GridLayoutManager,那麼就不需要滑動所以可以這樣設置(左、上、右、下) 38 | // int dragFlags = ItemTouchHelper.LEFT | ItemTouchHelper.UP | ItemTouchHelper.RIGHT | ItemTouchHelper.DOWN; 39 | 40 | // 如果想讓「移動」或是「滑動」,其中1個無效用則參數設為0即可 41 | // int dragFlags = 0; 42 | // int swipeFlags = 0; 43 | 44 | // 再透過makeMovementFlags()方法去設置 45 | return makeMovementFlags(dragFlags, swipeFlags); 46 | } 47 | 48 | /** 49 | * 移動完成後,要做甚麼事 50 | * 51 | * @param recyclerView 52 | * @param viewHolder 當前的手指正在移動的item 53 | * @param target 要被交換的item 54 | * @return 決定當次的移動是否要執行,true 執行 ; false 不執行 55 | */ 56 | @Override 57 | public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { 58 | return itemMoveSwipeListener.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); 59 | } 60 | 61 | /** 62 | * 滑動完成後,要做甚麼事 63 | * 64 | * @param viewHolder 65 | * @param direction 當前滑動的方向 66 | */ 67 | @Override 68 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { 69 | itemMoveSwipeListener.onItemSwipe(viewHolder.getAdapterPosition()); 70 | } 71 | 72 | /** 73 | * 當item被選取到的時候,要做甚麼事 74 | * 75 | * @param viewHolder 76 | * @param actionState 77 | */ 78 | @Override 79 | public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { 80 | super.onSelectedChanged(viewHolder, actionState); 81 | 82 | // 當item被選取到且是在移動的狀態下 83 | if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) { 84 | // 就將透明度為原來的70% 85 | viewHolder.itemView.setAlpha(0.7f); 86 | } 87 | } 88 | 89 | /** 90 | * 當事件完成後,可以在這個方法,將View做復原的動作 91 | * 92 | * @param recyclerView 93 | * @param viewHolder 94 | */ 95 | @Override 96 | public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { 97 | super.clearView(recyclerView, viewHolder); 98 | 99 | viewHolder.itemView.setAlpha(1.0f); 100 | } 101 | 102 | // 如果是Swipe,要Override這個方法,因為想做的效果是隨著滑動距離 103 | // 來改變當前的透明度。上述的方法並無法取得滑動距離。 104 | // 所以需在這個方法,來實現 105 | @Override 106 | public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, 107 | float dX, float dY, int actionState, boolean isCurrentlyActive) { 108 | super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); 109 | 110 | if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { 111 | // 取得控件的寬度 112 | float width = viewHolder.itemView.getWidth(); 113 | // 依照滑動的距離,來計算當前透明度的值 114 | float alphaValue = 1 - Math.abs(dX) / width; 115 | 116 | viewHolder.itemView.setAlpha(alphaValue); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/onboarding/OnboardingActivity.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign.onboarding; 2 | 3 | import android.animation.ArgbEvaluator; 4 | import android.graphics.Color; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.support.v4.app.Fragment; 8 | import android.support.v4.app.FragmentManager; 9 | import android.support.v4.app.FragmentPagerAdapter; 10 | import android.support.v4.view.ViewPager; 11 | import android.support.v7.app.AppCompatActivity; 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.widget.ImageView; 16 | import android.widget.TextView; 17 | 18 | import com.rayzhang.android.materialdesign.R; 19 | import com.rayzhang.android.materialdesign.widget.RZIndicatorView; 20 | 21 | public class OnboardingActivity extends AppCompatActivity implements View.OnClickListener { 22 | /** 23 | * Material Design Onboarding 24 | */ 25 | private ViewPager mViewPager; 26 | private TextView mTextSkip, mTextNext; 27 | private RZIndicatorView mRZIndicatorView; 28 | private SectionsPagerAdapter mSectionsPagerAdapter; 29 | // 設定過渡顏色的Array,數量是總頁數+1 30 | private int[] colors = {Color.parseColor("#ff9a96"), Color.parseColor("#74ceff"), Color.parseColor("#f1ce40"), 31 | Color.parseColor("#5b183f"), Color.parseColor("#ddeba1")}; 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_onboarding); 37 | 38 | mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); 39 | // Set up the ViewPager with the sections adapter. 40 | mViewPager = (ViewPager) findViewById(R.id.container); 41 | mViewPager.setAdapter(mSectionsPagerAdapter); 42 | mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { 43 | @Override 44 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 45 | /** 46 | * 使用顏色過渡類別 ArgbEvaluator() 47 | * 48 | * 3個參數分別為 49 | * 1. fraction : 過渡的起始&結束值 50 | * 2. startValue : 起始的顏色 51 | * 3. endValue : 結束的顏色 52 | */ 53 | // 這裡的結束顏色,就是下一頁的顏色。然而在最後一頁時,如果顏色Array數量沒+1,就會crash。也就是顏色Array數量要+1的原因 54 | int colorUpdate = (int) new ArgbEvaluator().evaluate(positionOffset, colors[position], colors[position + 1]); 55 | // 又或者去判斷是否為最後一頁,如果是就把顏色指定為第一頁的顏色 56 | //int colorUpdate = (int) new ArgbEvaluator().evaluate(positionOffset, colors[position], 57 | //colors[position + 1 == mViewPager.getChildCount() ? 0 : position + 1]); 58 | 59 | // 將過渡顏色設定為ViewPager的背景色 60 | mViewPager.setBackgroundColor(colorUpdate); 61 | // 當SDK >= 21時,將狀態列一併改變顏色 62 | if (Build.VERSION.SDK_INT >= 21) { 63 | getWindow().setStatusBarColor(colorUpdate); 64 | } 65 | } 66 | 67 | @Override 68 | public void onPageSelected(int position) { 69 | // 對應每個頁面時,textView就做相對應處理。並將IndicatorView的顯示,指定該頁面 70 | mTextSkip.setVisibility(position > 1 ? View.GONE : View.VISIBLE); 71 | mTextNext.setText(position > 1 ? "START" : "NEXT"); 72 | mRZIndicatorView.setCurPositon(position, false); 73 | } 74 | 75 | @Override 76 | public void onPageScrollStateChanged(int state) { 77 | 78 | } 79 | }); 80 | 81 | mTextSkip = (TextView) findViewById(R.id.mTextSkip); 82 | mTextNext = (TextView) findViewById(R.id.mTextNext); 83 | mTextSkip.setOnClickListener(this); 84 | mTextNext.setOnClickListener(this); 85 | // 自定義的Indicator View 86 | mRZIndicatorView = (RZIndicatorView) findViewById(R.id.mRZIndicatorView); 87 | mRZIndicatorView.setIndiCount(3); 88 | mRZIndicatorView.setIndicatorColor(Color.WHITE); 89 | mRZIndicatorView.setCurPositon(0, true); 90 | } 91 | 92 | @Override 93 | public void onClick(View v) { 94 | switch (v.getId()) { 95 | case R.id.mTextSkip: 96 | finish(); 97 | break; 98 | case R.id.mTextNext: 99 | int position = mViewPager.getCurrentItem(); 100 | if (position == 0 || position == 1) { 101 | mViewPager.setCurrentItem(position + 1); 102 | } else { 103 | finish(); 104 | } 105 | break; 106 | } 107 | } 108 | 109 | public static class PlaceholderFragment extends Fragment { 110 | private static final String ARG_SECTION_NUMBER = "section_number"; 111 | // 每頁圖片 112 | private int[] logos = {R.drawable.ic_twitter, R.drawable.ic_chrome, R.drawable.ic_android}; 113 | 114 | public PlaceholderFragment() { 115 | } 116 | 117 | public static PlaceholderFragment newInstance(int sectionNumber) { 118 | PlaceholderFragment fragment = new PlaceholderFragment(); 119 | Bundle args = new Bundle(); 120 | args.putInt(ARG_SECTION_NUMBER, sectionNumber); 121 | fragment.setArguments(args); 122 | return fragment; 123 | } 124 | 125 | @Override 126 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 127 | View rootView = inflater.inflate(R.layout.fragment_onboarding, container, false); 128 | 129 | ImageView mImgView = (ImageView) rootView.findViewById(R.id.mImgView); 130 | mImgView.setImageResource(logos[getArguments().getInt(ARG_SECTION_NUMBER)]); 131 | 132 | return rootView; 133 | } 134 | } 135 | 136 | public class SectionsPagerAdapter extends FragmentPagerAdapter { 137 | 138 | public SectionsPagerAdapter(FragmentManager fm) { 139 | super(fm); 140 | } 141 | 142 | @Override 143 | public Fragment getItem(int position) { 144 | // getItem is called to instantiate the fragment for the given page. 145 | // Return a PlaceholderFragment (defined as a static inner class below). 146 | return PlaceholderFragment.newInstance(position); 147 | } 148 | 149 | @Override 150 | public int getCount() { 151 | // Show 3 total pages. 152 | return 3; 153 | } 154 | 155 | @Override 156 | public CharSequence getPageTitle(int position) { 157 | switch (position) { 158 | case 0: 159 | return "SECTION 1"; 160 | case 1: 161 | return "SECTION 2"; 162 | case 2: 163 | return "SECTION 3"; 164 | } 165 | return null; 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /app/src/main/java/com/rayzhang/android/materialdesign/widget/RZIndicatorView.java: -------------------------------------------------------------------------------- 1 | package com.rayzhang.android.materialdesign.widget; 2 | 3 | import android.animation.Animator; 4 | import android.animation.ValueAnimator; 5 | import android.content.Context; 6 | import android.graphics.Canvas; 7 | import android.graphics.Color; 8 | import android.graphics.Paint; 9 | import android.support.annotation.ColorInt; 10 | import android.util.AttributeSet; 11 | import android.view.View; 12 | import android.view.animation.AccelerateDecelerateInterpolator; 13 | 14 | /** 15 | * Created by Ray on 2016/12/31. 16 | */ 17 | 18 | public class RZIndicatorView extends View { 19 | /** 20 | * 自訂義指示器 View 21 | */ 22 | private static final String TAG = RZIndicatorView.class.getSimpleName(); 23 | private Paint mPaint, mPaintExpand; 24 | // 半徑 25 | private float radius; 26 | // 直徑 27 | private float diameter; 28 | // 間距 29 | private float gap; 30 | // 數量 31 | private int indiCount; 32 | // 目前位置 33 | private int curPositon; 34 | // 紀錄總長度 35 | private int totalLen; 36 | // 選到Item動畫 37 | private ValueAnimator animator_expand; 38 | // 是否要繪製 39 | private boolean canDraw = false; 40 | // 擴散時的透明度 41 | private int expandAlphaValue = 255; 42 | // 擴散時的半徑 43 | private float expandRadius = 0f; 44 | // 動畫時間 45 | private static final int DURATION = 400; 46 | 47 | public RZIndicatorView(Context context) { 48 | this(context, null); 49 | } 50 | 51 | public RZIndicatorView(Context context, AttributeSet attrs) { 52 | this(context, attrs, 0); 53 | } 54 | 55 | public RZIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) { 56 | super(context, attrs, defStyleAttr); 57 | init(); 58 | } 59 | 60 | private void init() { 61 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 62 | mPaint.setDither(true); 63 | mPaint.setColor(Color.RED); 64 | mPaint.setStyle(Paint.Style.FILL_AND_STROKE); 65 | 66 | mPaintExpand = new Paint(Paint.ANTI_ALIAS_FLAG); 67 | mPaintExpand.setDither(true); 68 | mPaintExpand.setStyle(Paint.Style.FILL); 69 | 70 | gap = radius = 10f; 71 | diameter = radius * 2; 72 | curPositon = 0; 73 | indiCount = 0; 74 | setViewAnimatiorExpand(); 75 | } 76 | 77 | @Override 78 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 79 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 80 | // 只有1頁,所以不需要顯示 81 | if (indiCount <= 1) { 82 | return; 83 | } 84 | int widthMode = MeasureSpec.getMode(widthMeasureSpec); 85 | int heightMode = MeasureSpec.getMode(heightMeasureSpec); 86 | int widthSize = MeasureSpec.getSize(widthMeasureSpec); 87 | int heightSize = MeasureSpec.getSize(heightMeasureSpec); 88 | 89 | if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.EXACTLY) { 90 | widthSize = (int) (diameter * indiCount + radius * (indiCount + 1)); 91 | } else if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.AT_MOST) { 92 | heightSize = (int) diameter * 2; 93 | } else if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) { 94 | widthSize = (int) (diameter * indiCount + radius * (indiCount + 1)); 95 | heightSize = (int) diameter * 2; 96 | } else { 97 | // don't do anything 98 | } 99 | setMeasuredDimension(widthSize, heightSize); 100 | } 101 | 102 | @Override 103 | protected void onSizeChanged(int w, int h, int oldw, int oldh) { 104 | super.onSizeChanged(w, h, oldw, oldh); 105 | } 106 | 107 | @Override 108 | protected void onDraw(Canvas canvas) { 109 | super.onDraw(canvas); 110 | 111 | if (indiCount <= 1) return; 112 | int w = getWidth(); 113 | int h = getHeight(); 114 | float posX = diameter; 115 | if (w > totalLen) posX += (w - totalLen) / 2; 116 | 117 | for (int i = 0; i < indiCount; i++) { 118 | if (curPositon == i) { 119 | mPaint.setStyle(Paint.Style.FILL_AND_STROKE); 120 | } else { 121 | mPaint.setStyle(Paint.Style.STROKE); 122 | } 123 | //canvas.drawCircle(posX + (diameter + gap) * i, h - diameter, radius, mPaint); 124 | // 垂直水平 居中顯示 125 | canvas.drawCircle(posX + (diameter + gap) * i, h / 2, radius, mPaint); 126 | } 127 | if (canDraw) { 128 | mPaintExpand.setARGB(expandAlphaValue, 255, 80, 80); 129 | canvas.drawCircle(posX + (diameter + gap) * curPositon, h / 2, expandRadius, mPaintExpand); 130 | } 131 | } 132 | 133 | private void setViewAnimatiorExpand() { 134 | animator_expand = ValueAnimator.ofFloat(0f, diameter); 135 | animator_expand.setDuration(DURATION); 136 | animator_expand.setInterpolator(new AccelerateDecelerateInterpolator()); 137 | animator_expand.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 138 | @Override 139 | public void onAnimationUpdate(ValueAnimator animation) { 140 | expandRadius = (float) animation.getAnimatedValue(); 141 | expandAlphaValue = (int) (255 - (255 * expandRadius) / diameter); 142 | invalidate(); 143 | } 144 | }); 145 | animator_expand.addListener(new Animator.AnimatorListener() { 146 | @Override 147 | public void onAnimationStart(Animator animation) { 148 | canDraw = true; 149 | } 150 | 151 | @Override 152 | public void onAnimationEnd(Animator animation) { 153 | canDraw = false; 154 | } 155 | 156 | @Override 157 | public void onAnimationCancel(Animator animation) { 158 | 159 | } 160 | 161 | @Override 162 | public void onAnimationRepeat(Animator animation) { 163 | 164 | } 165 | }); 166 | } 167 | 168 | public void setRadius(float radius) { 169 | this.radius = radius; 170 | gap = radius; 171 | diameter = radius * 2; 172 | invalidate(); 173 | } 174 | 175 | public void setCurPositon(int curPositon, boolean isFirst) { 176 | this.curPositon = curPositon; 177 | invalidate(); 178 | if (!isFirst) animator_expand.start(); 179 | } 180 | 181 | public void setIndiCount(int indiCount) { 182 | this.indiCount = indiCount; 183 | totalLen = (int) (diameter * indiCount + radius * (indiCount + 1)); 184 | invalidate(); 185 | } 186 | 187 | public void setIndicatorColor(@ColorInt int color) { 188 | mPaint.setColor(color); 189 | //mPaintExpand.setColor(color); 190 | } 191 | 192 | public void setIndicatorColor(String color) { 193 | mPaint.setColor(Color.parseColor(color)); 194 | //mPaintExpand.setColor(Color.parseColor(color)); 195 | } 196 | 197 | 198 | private int dp2px(Context context, float dpValue) { 199 | final float scale = context.getResources().getDisplayMetrics().density; 200 | return (int) (dpValue * scale + 0.5f); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_arrow_back_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-hdpi/ic_arrow_back_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_delete_forever_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-hdpi/ic_delete_forever_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_favorite_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-hdpi/ic_favorite_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_google_play_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-hdpi/ic_google_play_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_arrow_back_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-mdpi/ic_arrow_back_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_delete_forever_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-mdpi/ic_delete_forever_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_favorite_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-mdpi/ic_favorite_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_google_play_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-mdpi/ic_google_play_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xhdpi/ic_android.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_arrow_back_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xhdpi/ic_arrow_back_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_bird_shape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xhdpi/ic_bird_shape.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xhdpi/ic_chrome.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_delete_forever_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xhdpi/ic_delete_forever_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_facebook_45dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xhdpi/ic_facebook_45dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_favorite_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xhdpi/ic_favorite_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_google_play_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xhdpi/ic_google_play_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_logout_45dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xhdpi/ic_logout_45dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xhdpi/ic_twitter.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_user_60dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xhdpi/ic_user_60dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xxhdpi/ic_android.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_arrow_back_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xxhdpi/ic_arrow_back_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_bird_shape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xxhdpi/ic_bird_shape.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xxhdpi/ic_chrome.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_delete_forever_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xxhdpi/ic_delete_forever_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_facebook_45dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xxhdpi/ic_facebook_45dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_favorite_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xxhdpi/ic_favorite_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_google_play_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xxhdpi/ic_google_play_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_logout_45dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xxhdpi/ic_logout_45dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xxhdpi/ic_twitter.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_user_60dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xxhdpi/ic_user_60dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_arrow_back_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xxxhdpi/ic_arrow_back_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_delete_forever_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xxxhdpi/ic_delete_forever_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_favorite_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xxxhdpi/ic_favorite_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_google_play_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable-xxxhdpi/ic_google_play_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/dialog_myself_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dialog_myself_left_but.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dialog_myself_right_but.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/twice_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ray00178/MaterialDesign/9f7d4f6c49a11ca804eaebd942b8eb6d607637b5/app/src/main/res/drawable/twice_1.jpg -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_asynctask.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 27 | 28 | 29 | 42 | 43 |