├── .gitignore ├── Doodle ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── cn │ │ │ └── hzw │ │ │ └── doodledemo │ │ │ ├── DemoApplication.java │ │ │ ├── MainActivity.java │ │ │ ├── MosaicDemo.java │ │ │ ├── ScaleGestureItemDemo.java │ │ │ └── guide │ │ │ ├── AdvancedDoodleView.java │ │ │ ├── DoodleGuideActivity.java │ │ │ ├── MiddleDoodleView.java │ │ │ ├── RectDoodleView.java │ │ │ └── SimpleDoodleView.java │ │ └── res │ │ ├── drawable-xxhdpi │ │ ├── ic_launcher.png │ │ └── thelittleprince2.png │ │ ├── drawable │ │ └── ic_launcher.png │ │ ├── layout │ │ ├── activity_guide.xml │ │ ├── activity_main.xml │ │ ├── activity_mosaic.xml │ │ └── activity_scale_gesture_item.xml │ │ ├── values-en │ │ └── strings.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ └── strings.xml ├── build.gradle ├── changes.md ├── doodle │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── cn │ │ │ └── hzw │ │ │ └── doodle │ │ │ ├── CopyLocation.java │ │ │ ├── DoodleActivity.java │ │ │ ├── DoodleBitmap.java │ │ │ ├── DoodleColor.java │ │ │ ├── DoodleItemBase.java │ │ │ ├── DoodleOnTouchGestureListener.java │ │ │ ├── DoodlePaintAttrs.java │ │ │ ├── DoodleParams.java │ │ │ ├── DoodlePath.java │ │ │ ├── DoodlePen.java │ │ │ ├── DoodleRotatableItemBase.java │ │ │ ├── DoodleSelectableItemBase.java │ │ │ ├── DoodleShape.java │ │ │ ├── DoodleText.java │ │ │ ├── DoodleTouchDetector.java │ │ │ ├── DoodleView.java │ │ │ ├── IDoodleListener.java │ │ │ ├── MyDoodleOnTouchGestureListener.java │ │ │ ├── core │ │ │ ├── IDoodle.java │ │ │ ├── IDoodleColor.java │ │ │ ├── IDoodleItem.java │ │ │ ├── IDoodleItemListener.java │ │ │ ├── IDoodlePen.java │ │ │ ├── IDoodleSelectableItem.java │ │ │ ├── IDoodleShape.java │ │ │ └── IDoodleTouchDetector.java │ │ │ ├── dialog │ │ │ ├── ColorPickerDialog.java │ │ │ ├── ColorPickerView.java │ │ │ └── DialogController.java │ │ │ ├── imagepicker │ │ │ ├── ImageLoader.java │ │ │ ├── ImageSelectorAdapter.java │ │ │ └── ImageSelectorView.java │ │ │ ├── occlusion │ │ │ └── OcclusionItem.java │ │ │ └── util │ │ │ ├── DrawUtil.java │ │ │ └── TransformUtil.java │ │ └── res │ │ ├── drawable-xxhdpi │ │ ├── doodle_bar_background.9.png │ │ ├── doodle_bar_progress.9.png │ │ ├── doodle_btn_back.png │ │ ├── doodle_btn_finish.png │ │ ├── doodle_hide_panel.png │ │ ├── doodle_hide_panel_pressed.png │ │ ├── doodle_ic_arrow.png │ │ ├── doodle_ic_clear.png │ │ ├── doodle_ic_copy.png │ │ ├── doodle_ic_eraser.png │ │ ├── doodle_ic_fill_circle.png │ │ ├── doodle_ic_fill_rect.png │ │ ├── doodle_ic_handwrite.png │ │ ├── doodle_ic_hollow_circle.png │ │ ├── doodle_ic_hollow_rect.png │ │ ├── doodle_ic_line.png │ │ ├── doodle_ic_mosaic.png │ │ ├── doodle_ic_move.png │ │ ├── doodle_ic_pen.png │ │ ├── doodle_ic_text.png │ │ ├── doodle_ic_texture.png │ │ ├── doodle_ic_undo.png │ │ ├── doodle_ic_undo_white.png │ │ ├── doodle_ic_zoomer.png │ │ ├── doodle_imageselector_image_selected.png │ │ ├── doodle_imageselector_loading.9.png │ │ ├── doodle_rotate.png │ │ ├── doodle_shader1.jpg │ │ ├── doodle_shader2.jpg │ │ ├── doodle_shader3.jpg │ │ ├── doodle_shader4.jpg │ │ ├── doodle_shader5.jpg │ │ ├── doodle_thumb_normal.png │ │ └── doodle_thumb_pressed.png │ │ ├── drawable │ │ ├── doodle_btn_effect_panel.xml │ │ ├── doodle_btn_effect_rect_line.xml │ │ ├── doodle_btn_effect_rect_pressed_black.xml │ │ ├── doodle_btn_effect_round.xml │ │ ├── doodle_seekbar_bg.xml │ │ ├── doodle_shape_circle_normal.xml │ │ ├── doodle_shape_circle_pressed.xml │ │ ├── doodle_shape_rect_pressed_black.xml │ │ ├── doodle_shape_rect_stroke_normal.xml │ │ ├── doodle_shape_rect_stroke_pressed.xml │ │ └── doodle_thumb_seekbarr.xml │ │ ├── layout │ │ ├── doodle_color_selector_dialog.xml │ │ ├── doodle_create_bitmap.xml │ │ ├── doodle_create_text.xml │ │ ├── doodle_dialog.xml │ │ ├── doodle_imageselector_item.xml │ │ ├── doodle_layout.xml │ │ ├── doodle_layout_image_selector.xml │ │ └── doodle_title_bar.xml │ │ ├── values-en │ │ └── strings.xml │ │ └── values │ │ ├── color.xml │ │ ├── dimen.xml │ │ └── strings.xml ├── extend.md ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew └── settings.gradle ├── LICENSE.txt ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ └── bugly_crashreport_upgrade-1.3.9.aar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── mmjang │ │ └── ankillusion │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── occlusion_model.html │ │ └── occlusion_model_v2.html │ ├── java │ │ └── com │ │ │ ├── ichi2 │ │ │ └── anki │ │ │ │ ├── FlashCardsContract.java │ │ │ │ └── api │ │ │ │ ├── AddContentApi.java │ │ │ │ ├── Basic2Model.java │ │ │ │ ├── BasicModel.java │ │ │ │ ├── NoteInfo.java │ │ │ │ └── Utils.java │ │ │ └── mmjang │ │ │ └── ankillusion │ │ │ ├── MyApplication.java │ │ │ ├── anki │ │ │ ├── AnkiDroidHelper.java │ │ │ ├── AnkiOcclusionExporter.java │ │ │ └── OcclusionCardModel.java │ │ │ ├── data │ │ │ ├── Constant.java │ │ │ ├── IOcclusionExporter.java │ │ │ ├── OcclusionExportType.java │ │ │ ├── OcclusionObject.java │ │ │ ├── OcclusionObjectListGenerator.java │ │ │ ├── OperationResult.java │ │ │ └── Settings.java │ │ │ ├── ui │ │ │ ├── AboutActivity.java │ │ │ ├── ImageActivity.java │ │ │ ├── LauncherActivity.java │ │ │ └── SettingsActivity.java │ │ │ └── utils │ │ │ ├── BuglyFileProvider.java │ │ │ └── Utils.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── alipay.jpg │ │ ├── bg_chip_state_list.xml │ │ ├── buymeacoffee.png │ │ ├── crop_button_selector.xml │ │ ├── ic_baseline_camera_alt_24px.xml │ │ ├── ic_baseline_close_24px.xml │ │ ├── ic_baseline_crop_24px.xml │ │ ├── ic_baseline_delete_forever_24px.xml │ │ ├── ic_baseline_done_24px.xml │ │ ├── ic_baseline_help_24px.xml │ │ ├── ic_baseline_photo_24px.xml │ │ ├── ic_baseline_rotate_right_24px.xml │ │ ├── ic_baseline_settings_20px.xml │ │ ├── ic_baseline_text_fields_24px.xml │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.xml │ │ ├── launcher_button_normal.xml │ │ ├── launcher_button_pressed.xml │ │ └── launcher_button_selector.xml │ │ ├── layout │ │ ├── activity_about.xml │ │ ├── activity_launcher.xml │ │ ├── activity_main.xml │ │ ├── activity_settings.xml │ │ ├── dialog_add_note.xml │ │ └── tag_chip_item.xml │ │ ├── menu │ │ ├── about_activity_menu.xml │ │ └── image_activity_menu.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── values-zh │ │ ├── arrays.xml │ │ └── strings.xml │ │ ├── values │ │ ├── arrays.xml │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ ├── file_paths.xml │ │ └── provider_paths.xml │ └── test │ └── java │ └── com │ └── mmjang │ └── ankillusion │ └── ExampleUnitTest.java ├── build.gradle ├── documentation-cn.md ├── documentation-en.md ├── etc ├── icons │ ├── baseline-camera_alt-24px.svg │ ├── baseline-close-24px.svg │ ├── baseline-crop-24px.svg │ ├── baseline-delete_forever-24px.svg │ ├── baseline-done-24px.svg │ ├── baseline-help-24px.svg │ ├── baseline-library_add-24px.svg │ ├── baseline-photo-24px.svg │ ├── baseline-rotate_right-24px.svg │ ├── baseline-settings-20px.svg │ ├── baseline-text_fields-24px.svg │ ├── ic_launcher - 副本.png │ └── ic_launcher.png └── pic │ ├── ankidoodle.gif │ ├── ankidroid.gif │ ├── enframe_2019-04-24-19-51-45.png │ ├── enframe_2019-04-24-19-58-18.png │ ├── enframe_2019-04-24-19-58-27.png │ ├── enframe_2019-04-24-19-58-42.png │ ├── enframe_2019-04-24-19-58-47.png │ ├── google play icon.png │ ├── google_play_big.png │ ├── mode_1.png │ ├── mode_2.png │ ├── mode_3.png │ └── poster.psd ├── frontend ├── anki_desktop.html ├── heart.jpg ├── test_canvas - 副本.html └── test_canvas.html ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── privacy_policy.md └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | *.db 4 | *.apk 5 | /local.properties 6 | /.idea/workspace.xml 7 | /.idea/libraries 8 | /app/release/ 9 | .DS_Store 10 | /build 11 | /captures 12 | /folioreader/build 13 | /Doodle/build 14 | .externalNativeBuild 15 | .idea 16 | 17 | # Custom 18 | _site 19 | 20 | # Ant 21 | MANIFEST.MF 22 | ./*.jar 23 | build.num 24 | build 25 | 26 | # ADT 27 | .classpath 28 | .project 29 | .settings 30 | local.properties 31 | bin 32 | gen 33 | _layouts 34 | proguard.cfg 35 | 36 | # OSX 37 | .DS_Store 38 | 39 | # Github 40 | gh-pages 41 | 42 | # Gradle 43 | .gradle 44 | build 45 | 46 | # IDEA 47 | *.iml 48 | *.ipr 49 | *.iws 50 | out 51 | .idea 52 | 53 | # Maven 54 | target 55 | release.properties 56 | pom.xml.* 57 | 58 | # Readium DRM LCP 59 | liblcp.aar -------------------------------------------------------------------------------- /Doodle/.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle 2 | .gradle 3 | gradlew.bat 4 | build 5 | local.properties 6 | reports 7 | 8 | # Maven 9 | target 10 | pom.xml.* 11 | release.properties 12 | gen-external-apklibs 13 | 14 | # Eclipse 15 | .classpath 16 | .project 17 | .settings 18 | eclipsebin 19 | 20 | # IntelliJ IDEA 21 | .idea 22 | *.iml 23 | *.ipl 24 | *.iws 25 | classes/ 26 | idea-classes/ 27 | coverage-error.log 28 | 29 | # Android 30 | gen 31 | bin 32 | project.properties 33 | out 34 | 35 | # Finder 36 | .DS_Store -------------------------------------------------------------------------------- /Doodle/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /Doodle/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion COMPILE_SDK_VERSION as int 5 | 6 | defaultConfig { 7 | applicationId "cn.hzw.doodledemo" 8 | minSdkVersion MIN_SDK_VERSION as int 9 | targetSdkVersion TARGET_SDK_VERSION as int 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | implementation fileTree(include: ['*.jar'], dir: 'libs') 24 | implementation project(':Doodle:doodle') 25 | implementation ('cn.hzw.imageselector:library:1.0'){ 26 | transitive = false 27 | } 28 | 29 | /* // test 30 | debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.2' 31 | releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.2' 32 | // Optional, if you use support library fragments: 33 | debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.2'*/ 34 | } 35 | -------------------------------------------------------------------------------- /Doodle/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 /home/huangziwei/android-sdk-linux/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 | -------------------------------------------------------------------------------- /Doodle/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Doodle/app/src/main/java/cn/hzw/doodledemo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package cn.hzw.doodledemo; 2 | 3 | import android.app.Application; 4 | 5 | public class DemoApplication extends Application { 6 | @Override 7 | public void onCreate() { 8 | super.onCreate(); 9 | /* if (LeakCanary.isInAnalyzerProcess(this)) { 10 | // This process is dedicated to LeakCanary for heap analysis. 11 | // You should not init your app in this process. 12 | return; 13 | } 14 | LeakCanary.install(this);*/ 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Doodle/app/src/main/java/cn/hzw/doodledemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package cn.hzw.doodledemo; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.graphics.Color; 6 | import android.os.Bundle; 7 | import android.text.TextUtils; 8 | import android.view.View; 9 | import android.widget.TextView; 10 | import android.widget.Toast; 11 | 12 | import java.util.ArrayList; 13 | 14 | import cn.forward.androids.utils.LogUtil; 15 | import cn.hzw.doodle.DoodleActivity; 16 | import cn.hzw.doodle.DoodleParams; 17 | import cn.hzw.doodle.DoodleView; 18 | import cn.hzw.doodledemo.guide.DoodleGuideActivity; 19 | import cn.hzw.imageselector.ImageLoader; 20 | import cn.hzw.imageselector.ImageSelectorActivity; 21 | 22 | public class MainActivity extends Activity { 23 | 24 | public static final int REQ_CODE_SELECT_IMAGE = 100; 25 | public static final int REQ_CODE_DOODLE = 101; 26 | private TextView mPath; 27 | 28 | @Override 29 | protected void onCreate(Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_main); 32 | 33 | findViewById(R.id.btn_select_image).setOnClickListener(new View.OnClickListener() { 34 | @Override 35 | public void onClick(View v) { 36 | ImageSelectorActivity.startActivityForResult(REQ_CODE_SELECT_IMAGE, MainActivity.this, null, false); 37 | } 38 | }); 39 | 40 | findViewById(R.id.btn_guide).setOnClickListener(new View.OnClickListener() { 41 | @Override 42 | public void onClick(View v) { 43 | startActivity(new Intent(getApplicationContext(), DoodleGuideActivity.class)); 44 | } 45 | }); 46 | 47 | findViewById(R.id.btn_mosaic).setOnClickListener(new View.OnClickListener() { 48 | @Override 49 | public void onClick(View v) { 50 | startActivity(new Intent(getApplicationContext(), MosaicDemo.class)); 51 | } 52 | }); 53 | findViewById(R.id.btn_scale_gesture).setOnClickListener(new View.OnClickListener() { 54 | @Override 55 | public void onClick(View v) { 56 | startActivity(new Intent(getApplicationContext(), ScaleGestureItemDemo.class)); 57 | } 58 | }); 59 | mPath = (TextView) findViewById(R.id.img_path); 60 | } 61 | 62 | @Override 63 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 64 | super.onActivityResult(requestCode, resultCode, data); 65 | if (requestCode == REQ_CODE_SELECT_IMAGE) { 66 | if (data == null) { 67 | return; 68 | } 69 | ArrayList list = data.getStringArrayListExtra(ImageSelectorActivity.KEY_PATH_LIST); 70 | if (list != null && list.size() > 0) { 71 | LogUtil.d("Doodle", list.get(0)); 72 | 73 | // 涂鸦参数 74 | DoodleParams params = new DoodleParams(); 75 | params.mIsFullScreen = true; 76 | // 图片路径 77 | params.mImagePath = list.get(0); 78 | // 初始画笔大小 79 | params.mPaintUnitSize = DoodleView.DEFAULT_SIZE; 80 | // 画笔颜色 81 | params.mPaintColor = Color.RED; 82 | // 是否支持缩放item 83 | params.mSupportScaleItem = true; 84 | // 启动涂鸦页面 85 | DoodleActivity.startActivityForResult(MainActivity.this, params, REQ_CODE_DOODLE); 86 | } 87 | } else if (requestCode == REQ_CODE_DOODLE) { 88 | if (data == null) { 89 | return; 90 | } 91 | if (resultCode == DoodleActivity.RESULT_OK) { 92 | String path = data.getStringExtra(DoodleActivity.KEY_IMAGE_PATH); 93 | if (TextUtils.isEmpty(path)) { 94 | return; 95 | } 96 | ImageLoader.getInstance(this).display(findViewById(R.id.img), path); 97 | mPath.setText(path); 98 | } else if (resultCode == DoodleActivity.RESULT_ERROR) { 99 | Toast.makeText(getApplicationContext(), "error", Toast.LENGTH_SHORT).show(); 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Doodle/app/src/main/java/cn/hzw/doodledemo/MosaicDemo.java: -------------------------------------------------------------------------------- 1 | package cn.hzw.doodledemo; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.graphics.Canvas; 7 | import android.graphics.Color; 8 | import android.graphics.Matrix; 9 | import android.graphics.Paint; 10 | import android.os.Bundle; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.Toast; 14 | 15 | import cn.hzw.doodle.DoodleColor; 16 | import cn.hzw.doodle.DoodleOnTouchGestureListener; 17 | import cn.hzw.doodle.DoodleShape; 18 | import cn.hzw.doodle.DoodleTouchDetector; 19 | import cn.hzw.doodle.DoodleView; 20 | import cn.hzw.doodle.IDoodleListener; 21 | import cn.hzw.doodle.core.IDoodle; 22 | import cn.hzw.doodle.core.IDoodleItem; 23 | import cn.hzw.doodle.core.IDoodlePen; 24 | 25 | /** 26 | * Mosaic effect 27 | */ 28 | public class MosaicDemo extends Activity { 29 | private DoodleView doodleView; 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.activity_mosaic); 35 | 36 | // step 1 37 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.thelittleprince2); 38 | doodleView = new DoodleView(this, bitmap, new IDoodleListener() { 39 | @Override 40 | public void onSaved(IDoodle doodle, Bitmap doodleBitmap, Runnable callback) { 41 | Toast.makeText(MosaicDemo.this, "onSaved", Toast.LENGTH_SHORT).show(); 42 | } 43 | 44 | @Override 45 | public void onReady(IDoodle doodle) { 46 | doodle.setSize(30 * doodle.getUnitSize()); 47 | } 48 | }); 49 | 50 | // step 2 51 | DoodleOnTouchGestureListener touchGestureListener = new DoodleOnTouchGestureListener(doodleView, null); 52 | DoodleTouchDetector touchDetector = new DoodleTouchDetector(this, touchGestureListener); 53 | doodleView.setDefaultTouchDetector(touchDetector); 54 | 55 | // step 3 56 | doodleView.setPen(new MosaicPen()); 57 | //doodleView.setShape(DoodleShape.HAND_WRITE); 58 | doodleView.setShape(DoodleShape.FILL_RECT); 59 | doodleView.setColor(new DoodleColor(Color.RED)); 60 | // setColor 61 | //findViewById(R.id.btn_mosaic_x3).performClick(); // see setMosaicLevel(View view) 62 | 63 | // step 4 64 | ViewGroup container = (ViewGroup) findViewById(R.id.doodle_container); 65 | container.addView(doodleView); 66 | } 67 | 68 | private DoodleColor getMosaicColor(int level) { 69 | Matrix matrix = new Matrix(); 70 | matrix.setScale(1f / level, 1f / level); 71 | Bitmap mosaicBitmap = Bitmap.createBitmap(doodleView.getBitmap(), 72 | 0, 0, doodleView.getBitmap().getWidth(), doodleView.getBitmap().getHeight(), matrix, true); 73 | matrix.reset(); 74 | matrix.setScale(level, level); 75 | DoodleColor doodleColor = new DoodleColor(mosaicBitmap, matrix); 76 | doodleColor.setLevel(level); 77 | return doodleColor; 78 | } 79 | 80 | public void setMosaicLevel(View view) { 81 | if (view.getId() == R.id.btn_mosaic_x1) { 82 | doodleView.setColor(getMosaicColor(5)); 83 | } else if (view.getId() == R.id.btn_mosaic_x2) { 84 | doodleView.setColor(getMosaicColor(20)); 85 | } else if (view.getId() == R.id.btn_mosaic_x3) { 86 | doodleView.setColor(getMosaicColor(50)); 87 | } 88 | } 89 | 90 | /* 91 | Though setting a new pen here is not necessary, the design-based specification should do this. 92 | 虽然这里设置新的画笔不是必要的,但是基于设计的规范应该这样做。马赛克画笔在概念上不同于其他画笔, 93 | */ 94 | private static class MosaicPen implements IDoodlePen { 95 | @Override 96 | public void config(IDoodleItem doodleItem, Paint paint) { 97 | } 98 | 99 | @Override 100 | public void drawHelpers(Canvas canvas, IDoodle doodle) { 101 | } 102 | 103 | @Override 104 | public IDoodlePen copy() { 105 | return this; 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Doodle/app/src/main/java/cn/hzw/doodledemo/guide/DoodleGuideActivity.java: -------------------------------------------------------------------------------- 1 | package cn.hzw.doodledemo.guide; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.os.Bundle; 7 | import android.view.ViewGroup; 8 | 9 | import cn.hzw.doodledemo.R; 10 | 11 | public class DoodleGuideActivity extends Activity { 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_guide); 17 | 18 | // 初级涂鸦 19 | ViewGroup simpleContainer = (ViewGroup) findViewById(R.id.container_simple_doodle); 20 | SimpleDoodleView simpleDoodleView = new SimpleDoodleView(this); 21 | simpleContainer.addView(simpleDoodleView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 22 | 23 | // 中级涂鸦 24 | ViewGroup middleContainer = (ViewGroup) findViewById(R.id.container_middle_doodle); 25 | MiddleDoodleView middleDoodleView = new MiddleDoodleView(this); 26 | middleContainer.addView(middleDoodleView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 27 | 28 | // 高级级涂鸦 29 | ViewGroup advancedContainer = (ViewGroup) findViewById(R.id.container_advanced_doodle); 30 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.thelittleprince2); 31 | AdvancedDoodleView advancedDoodleView = new AdvancedDoodleView(this, bitmap); 32 | advancedContainer.addView(advancedDoodleView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 33 | 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Doodle/app/src/main/java/cn/hzw/doodledemo/guide/SimpleDoodleView.java: -------------------------------------------------------------------------------- 1 | package cn.hzw.doodledemo.guide; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.Path; 8 | import android.util.Log; 9 | import android.view.MotionEvent; 10 | import android.view.View; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | import cn.forward.androids.TouchGestureDetector; 16 | 17 | /** 18 | * 初级涂鸦 19 | * 没有图片 仅支持 手绘 20 | * Created on 24/06/2018. 21 | */ 22 | public class SimpleDoodleView extends View { 23 | 24 | private final static String TAG = "SimpleDoodleView"; 25 | 26 | private Paint mPaint = new Paint(); 27 | private List mPathList = new ArrayList<>(); // 保存涂鸦轨迹的集合 28 | private TouchGestureDetector mTouchGestureDetector; // 触摸手势监听 29 | private float mLastX, mLastY; 30 | private Path mCurrentPath; // 当前的涂鸦轨迹 31 | 32 | public SimpleDoodleView(Context context) { 33 | super(context); 34 | // 设置画笔 35 | mPaint.setColor(Color.RED); 36 | mPaint.setStyle(Paint.Style.STROKE); 37 | mPaint.setStrokeWidth(20); 38 | mPaint.setAntiAlias(true); 39 | mPaint.setStrokeCap(Paint.Cap.ROUND); 40 | 41 | // 由手势识别器处理手势 42 | mTouchGestureDetector = new TouchGestureDetector(getContext(), new TouchGestureDetector.OnTouchGestureListener() { 43 | 44 | @Override 45 | public void onScrollBegin(MotionEvent e) { // 滑动开始 46 | Log.d(TAG, "onScrollBegin: "); 47 | mCurrentPath = new Path(); // 新的涂鸦 48 | mPathList.add(mCurrentPath); // 添加的集合中 49 | mCurrentPath.moveTo(e.getX(), e.getY()); 50 | mLastX = e.getX(); 51 | mLastY = e.getY(); 52 | invalidate(); // 刷新 53 | } 54 | 55 | @Override 56 | public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // 滑动中 57 | Log.d(TAG, "onScroll: " + e2.getX() + " " + e2.getY()); 58 | mCurrentPath.quadTo( 59 | mLastX, 60 | mLastY, 61 | (e2.getX() + mLastX) / 2, 62 | (e2.getY() + mLastY) / 2); // 使用贝塞尔曲线 让涂鸦轨迹更圆滑 63 | mLastX = e2.getX(); 64 | mLastY = e2.getY(); 65 | invalidate(); // 刷新 66 | return true; 67 | } 68 | 69 | @Override 70 | public void onScrollEnd(MotionEvent e) { // 滑动结束 71 | Log.d(TAG, "onScrollEnd: "); 72 | mCurrentPath.quadTo( 73 | mLastX, 74 | mLastY, 75 | (e.getX() + mLastX) / 2, 76 | (e.getY() + mLastY) / 2); // 使用贝塞尔曲线 让涂鸦轨迹更圆滑 77 | mCurrentPath = null; // 轨迹结束 78 | invalidate(); // 刷新 79 | } 80 | 81 | }); 82 | } 83 | 84 | @Override 85 | public boolean dispatchTouchEvent(MotionEvent event) { 86 | boolean consumed = mTouchGestureDetector.onTouchEvent(event); // 由手势识别器处理手势 87 | if (!consumed) { 88 | return super.dispatchTouchEvent(event); 89 | } 90 | return true; 91 | } 92 | 93 | @Override 94 | protected void onDraw(Canvas canvas) { 95 | for (Path path : mPathList) { // 绘制涂鸦轨迹 96 | canvas.drawPath(path, mPaint); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Doodle/app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmjang/Ankillusion/72c60e134557b1715bfe9f607f89f8fa4c8edde2/Doodle/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Doodle/app/src/main/res/drawable-xxhdpi/thelittleprince2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmjang/Ankillusion/72c60e134557b1715bfe9f607f89f8fa4c8edde2/Doodle/app/src/main/res/drawable-xxhdpi/thelittleprince2.png -------------------------------------------------------------------------------- /Doodle/app/src/main/res/drawable/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmjang/Ankillusion/72c60e134557b1715bfe9f607f89f8fa4c8edde2/Doodle/app/src/main/res/drawable/ic_launcher.png -------------------------------------------------------------------------------- /Doodle/app/src/main/res/layout/activity_guide.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 22 | 23 | 24 | 30 | 31 | 39 | 40 | 41 | 47 | 48 | 56 | 57 | -------------------------------------------------------------------------------- /Doodle/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 |