├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── misc.xml ├── modules.xml ├── scopes │ └── scope_settings.xml ├── vcs.xml └── workspace.xml ├── AndroidManifest.xml ├── README.md ├── ant.properties ├── bezierCurve.iml ├── build.xml ├── local.properties ├── out └── production │ └── bezierCurve │ ├── bezierCurve.apk │ ├── bezierCurve.unaligned.apk │ └── com │ └── example │ └── bezierCurve │ ├── BuildConfig.class │ ├── MyActivity$1.class │ ├── MyActivity.class │ ├── Pager.class │ ├── PagerFactory.class │ ├── R$attr.class │ ├── R$drawable.class │ ├── R$layout.class │ ├── R$string.class │ └── R.class ├── proguard-project.txt ├── project.properties ├── res ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-ldpi │ └── ic_launcher.png ├── drawable-mdpi │ ├── ic_launcher.png │ ├── one.jpg │ ├── three.jpg │ └── two.jpg ├── drawable-xhdpi │ └── ic_launcher.png ├── layout │ └── main.xml └── values │ └── strings.xml ├── src └── com │ └── example │ └── bezierCurve │ ├── MyActivity.java │ ├── Pager.java │ └── PagerFactory.java └── wiki └── result.gif /.idea/.name: -------------------------------------------------------------------------------- 1 | bezierCurve -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 34 | 35 | 36 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 86 | 87 | 88 | true 89 | 90 | 91 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 127 | 128 | 129 | 130 | 133 | 134 | 137 | 138 | 139 | 140 | 143 | 144 | 147 | 148 | 151 | 152 | 155 | 156 | 157 | 158 | 161 | 162 | 165 | 166 | 169 | 170 | 171 | 172 | 175 | 176 | 179 | 180 | 183 | 184 | 187 | 188 | 189 | 190 | 193 | 194 | 197 | 198 | 201 | 202 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 248 | 249 | 250 | 251 | 252 | 253 | 260 | 261 | 262 | 280 | 281 | 282 | 286 | 287 | 288 | 299 | 300 | 301 | 314 | 315 | 316 | 317 | 335 | 342 | 343 | 344 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 1439173802209 381 | 393 | 394 | 395 | 396 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 439 | 442 | 443 | 444 | 446 | 447 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### **成果物** 2 | 3 | ![result](https://github.com/skypanda100/BezierCurve/blob/master/wiki/result.gif) 4 | -------------------------------------------------------------------------------- /ant.properties: -------------------------------------------------------------------------------- 1 | # This file is used to override default values used by the Ant build system. 2 | # 3 | # This file must be checked into Version Control Systems, as it is 4 | # integral to the build system of your project. 5 | 6 | # This file is only used by the Ant script. 7 | 8 | # You can use this to override default values such as 9 | # 'source.dir' for the location of your java source folder and 10 | # 'out.dir' for the location of your output folder. 11 | 12 | # You can also use it define how the release builds are signed by declaring 13 | # the following properties: 14 | # 'key.store' for the location of your keystore and 15 | # 'key.alias' for the name of the key to use. 16 | # The password will be asked during the build when you use the 'release' target. 17 | 18 | -------------------------------------------------------------------------------- /bezierCurve.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 29 | 30 | 31 | 35 | 36 | 37 | 38 | 39 | 40 | 49 | 50 | 51 | 52 | 56 | 57 | 69 | 70 | 71 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /local.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must *NOT* be checked into Version Control Systems, 5 | # as it contains information specific to your local configuration. 6 | 7 | # location of the SDK. This is only used by Ant 8 | # For customization when using a Version Control System, please read the 9 | # header note. 10 | sdk.dir=F:\\android_eclipse_sdk\\adt-bundle-windows-x86_64-20140702\\sdk 11 | -------------------------------------------------------------------------------- /out/production/bezierCurve/bezierCurve.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/out/production/bezierCurve/bezierCurve.apk -------------------------------------------------------------------------------- /out/production/bezierCurve/bezierCurve.unaligned.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/out/production/bezierCurve/bezierCurve.unaligned.apk -------------------------------------------------------------------------------- /out/production/bezierCurve/com/example/bezierCurve/BuildConfig.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/out/production/bezierCurve/com/example/bezierCurve/BuildConfig.class -------------------------------------------------------------------------------- /out/production/bezierCurve/com/example/bezierCurve/MyActivity$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/out/production/bezierCurve/com/example/bezierCurve/MyActivity$1.class -------------------------------------------------------------------------------- /out/production/bezierCurve/com/example/bezierCurve/MyActivity.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/out/production/bezierCurve/com/example/bezierCurve/MyActivity.class -------------------------------------------------------------------------------- /out/production/bezierCurve/com/example/bezierCurve/Pager.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/out/production/bezierCurve/com/example/bezierCurve/Pager.class -------------------------------------------------------------------------------- /out/production/bezierCurve/com/example/bezierCurve/PagerFactory.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/out/production/bezierCurve/com/example/bezierCurve/PagerFactory.class -------------------------------------------------------------------------------- /out/production/bezierCurve/com/example/bezierCurve/R$attr.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/out/production/bezierCurve/com/example/bezierCurve/R$attr.class -------------------------------------------------------------------------------- /out/production/bezierCurve/com/example/bezierCurve/R$drawable.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/out/production/bezierCurve/com/example/bezierCurve/R$drawable.class -------------------------------------------------------------------------------- /out/production/bezierCurve/com/example/bezierCurve/R$layout.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/out/production/bezierCurve/com/example/bezierCurve/R$layout.class -------------------------------------------------------------------------------- /out/production/bezierCurve/com/example/bezierCurve/R$string.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/out/production/bezierCurve/com/example/bezierCurve/R$string.class -------------------------------------------------------------------------------- /out/production/bezierCurve/com/example/bezierCurve/R.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/out/production/bezierCurve/com/example/bezierCurve/R.class -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-20 15 | -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/one.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/res/drawable-mdpi/one.jpg -------------------------------------------------------------------------------- /res/drawable-mdpi/three.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/res/drawable-mdpi/three.jpg -------------------------------------------------------------------------------- /res/drawable-mdpi/two.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/res/drawable-mdpi/two.jpg -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | bezierCurve 4 | 5 | -------------------------------------------------------------------------------- /src/com/example/bezierCurve/MyActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.bezierCurve; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Activity; 5 | import android.content.pm.ApplicationInfo; 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapFactory; 8 | import android.graphics.Canvas; 9 | import android.graphics.Matrix; 10 | import android.os.Build; 11 | import android.os.Bundle; 12 | import android.util.DisplayMetrics; 13 | import android.util.Log; 14 | import android.view.MotionEvent; 15 | import android.view.View; 16 | import android.view.ViewGroup; 17 | import android.widget.FrameLayout; 18 | 19 | import java.io.InputStream; 20 | 21 | public class MyActivity extends Activity { 22 | private Pager pager; 23 | private PagerFactory pagerFactory; 24 | private Bitmap currentBitmap, mCurPageBitmap, mNextPageBitmap; 25 | private Canvas mCurPageCanvas, mNextPageCanvas; 26 | private static final String[] pages = {"one", "two", "three"}; 27 | private int screenWidth; 28 | private int screenHeight; 29 | 30 | /** 31 | * Called when the activity is first created. 32 | */ 33 | @Override 34 | public void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.main); 37 | 38 | initView(); 39 | } 40 | 41 | private void initView() { 42 | 43 | DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); 44 | screenWidth = displayMetrics.widthPixels; 45 | screenHeight = displayMetrics.heightPixels; 46 | pager = new Pager(this, screenWidth, screenHeight); 47 | 48 | FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 49 | addContentView(pager, layoutParams); 50 | 51 | mCurPageBitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888); 52 | mNextPageBitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888); 53 | 54 | mCurPageCanvas = new Canvas(mCurPageBitmap); 55 | mNextPageCanvas = new Canvas(mNextPageBitmap); 56 | pagerFactory = new PagerFactory(getApplicationContext()); 57 | 58 | pager.setBitmaps(mCurPageBitmap, mCurPageBitmap); 59 | loadImage(mCurPageCanvas, 0); 60 | 61 | pager.setOnTouchListener(new View.OnTouchListener() { 62 | 63 | private int count = pages.length; 64 | private int currentIndex = 0; 65 | private int lastIndex = 0; 66 | private Bitmap lastBitmap = null; 67 | 68 | @Override 69 | public boolean onTouch(View v, MotionEvent e) { 70 | boolean ret = false; 71 | if (v == pager) { 72 | if (e.getAction() == MotionEvent.ACTION_DOWN) { 73 | pager.calcCornerXY(e.getX(), e.getY()); 74 | 75 | lastBitmap = currentBitmap; 76 | lastIndex = currentIndex; 77 | 78 | pagerFactory.onDraw(mCurPageCanvas, currentBitmap); 79 | if (pager.DragToRight()) { // 向右滑动,显示前一页 80 | if (currentIndex == 0) return false; 81 | pager.abortAnimation(); 82 | currentIndex--; 83 | loadImage(mNextPageCanvas, currentIndex); 84 | } else { // 向左滑动,显示后一页 85 | if (currentIndex + 1 == count) return false; 86 | pager.abortAnimation(); 87 | currentIndex++; 88 | loadImage(mNextPageCanvas, currentIndex); 89 | } 90 | } else if (e.getAction() == MotionEvent.ACTION_MOVE) { 91 | 92 | } else if (e.getAction() == MotionEvent.ACTION_UP) { 93 | if (!pager.canDragOver()) { 94 | currentIndex = lastIndex; 95 | currentBitmap = lastBitmap; 96 | } 97 | } 98 | 99 | ret = pager.doTouchEvent(e); 100 | return ret; 101 | } 102 | return false; 103 | } 104 | }); 105 | } 106 | 107 | private void loadImage(final Canvas canvas, int index) { 108 | Bitmap bitmap = getBitmap(pages[index]); 109 | currentBitmap = bitmap; 110 | pagerFactory.onDraw(canvas, bitmap); 111 | pager.setBitmaps(mCurPageBitmap, mNextPageBitmap); 112 | pager.postInvalidate(); 113 | } 114 | 115 | private Bitmap getBitmap(String name) { 116 | BitmapFactory.Options opt = new BitmapFactory.Options(); 117 | opt.inPreferredConfig = Bitmap.Config.RGB_565; 118 | opt.inPurgeable = true; 119 | opt.inInputShareable = true; 120 | ApplicationInfo appInfo = getApplicationInfo(); 121 | int resID = getResources().getIdentifier(name, "drawable", appInfo.packageName); 122 | InputStream is = getResources().openRawResource(resID); 123 | Bitmap tempBitmap = BitmapFactory.decodeStream(is, null, opt); 124 | int width = tempBitmap.getWidth(); 125 | int height = tempBitmap.getHeight(); 126 | Matrix matrix = new Matrix(); 127 | matrix.postScale(((float)screenWidth)/width, ((float)screenHeight)/height); 128 | Bitmap bitmap = Bitmap.createBitmap(tempBitmap, 0, 0, width, height, matrix, true); 129 | return bitmap; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/com/example/bezierCurve/Pager.java: -------------------------------------------------------------------------------- 1 | package com.example.bezierCurve; 2 | 3 | import android.content.Context; 4 | import android.graphics.*; 5 | import android.graphics.drawable.GradientDrawable; 6 | import android.util.Log; 7 | import android.view.MotionEvent; 8 | import android.view.View; 9 | import android.widget.Scroller; 10 | 11 | public class Pager extends View { 12 | 13 | private int mWidth = 1280; 14 | private int mHeight = 768; 15 | private int mCornerX = 0; // 拖拽点对应的页脚 16 | private int mCornerY = 0; 17 | private Path mPath0; 18 | private Path mPath1; 19 | Bitmap mCurPageBitmap = null; // 当前页 20 | Bitmap mNextPageBitmap = null; 21 | 22 | PointF mTouch = new PointF(); // 拖拽点 23 | PointF mBezierStart1 = new PointF(); // 贝塞尔曲线起始点 24 | PointF mBezierControl1 = new PointF(); // 贝塞尔曲线控制点 25 | PointF mBeziervertex1 = new PointF(); // 贝塞尔曲线顶点 26 | PointF mBezierEnd1 = new PointF(); // 贝塞尔曲线结束点 27 | 28 | PointF mBezierStart2 = new PointF(); // 另一条贝塞尔曲线 29 | PointF mBezierControl2 = new PointF(); 30 | PointF mBeziervertex2 = new PointF(); 31 | PointF mBezierEnd2 = new PointF(); 32 | 33 | float mMiddleX; 34 | float mMiddleY; 35 | float mDegrees; 36 | float mTouchToCornerDis; 37 | ColorMatrixColorFilter mColorMatrixFilter; 38 | Matrix mMatrix; 39 | float[] mMatrixArray = { 0, 0, 0, 0, 0, 0, 0, 0, 1.0f }; 40 | 41 | boolean mIsRTandLB; // 是否属于右、上、左、下 42 | float mMaxLength = (float) Math.hypot(mWidth, mHeight); 43 | int[] mBackShadowColors; 44 | int[] mFrontShadowColors; 45 | GradientDrawable mBackShadowDrawableLR; 46 | GradientDrawable mBackShadowDrawableRL; 47 | GradientDrawable mFolderShadowDrawableLR; 48 | GradientDrawable mFolderShadowDrawableRL; 49 | 50 | GradientDrawable mFrontShadowDrawableHBT; 51 | GradientDrawable mFrontShadowDrawableHTB; 52 | GradientDrawable mFrontShadowDrawableVLR; 53 | GradientDrawable mFrontShadowDrawableVRL; 54 | 55 | Paint mPaint; 56 | Scroller mScroller; 57 | 58 | public Pager(Context context, int screenWidth, int screenHeight) { 59 | super(context); 60 | 61 | this.mWidth = screenWidth; // Pager 宽和高 62 | this.mHeight = screenHeight; 63 | 64 | mPath0 = new Path(); 65 | mPath1 = new Path(); 66 | createDrawable(); 67 | 68 | mPaint = new Paint(); 69 | mPaint.setStyle(Paint.Style.FILL); 70 | 71 | ColorMatrix cm = new ColorMatrix(); 72 | float array[] = { 0.55f, 0, 0, 0, 80.0f, 0, 0.55f, 0, 0, 80.0f, 0, 0, 73 | 0.55f, 0, 80.0f, 0, 0, 0, 0.2f, 0 }; 74 | cm.set(array); 75 | mColorMatrixFilter = new ColorMatrixColorFilter(cm); 76 | mMatrix = new Matrix(); 77 | mScroller = new Scroller(getContext()); 78 | 79 | mTouch.x = 0.01f; // 不让x,y为0,否则在点计算时会有问题 80 | mTouch.y = 0.01f; 81 | } 82 | 83 | /** 计算拖拽点对应的拖拽脚 */ 84 | public void calcCornerXY(float x, float y) { 85 | if (x <= mWidth / 2) 86 | mCornerX = 0; 87 | else 88 | mCornerX = mWidth; 89 | if (y <= mHeight / 2) 90 | mCornerY = 0; 91 | else 92 | mCornerY = mHeight; 93 | if ((mCornerX == 0 && mCornerY == mHeight) || (mCornerX == mWidth && mCornerY == 0)) 94 | mIsRTandLB = true; 95 | else 96 | mIsRTandLB = false; 97 | } 98 | 99 | public boolean doTouchEvent(MotionEvent event) { 100 | if (event.getAction() == MotionEvent.ACTION_MOVE) { 101 | mTouch.x = event.getX(); 102 | mTouch.y = event.getY(); 103 | this.postInvalidate(); 104 | } 105 | if (event.getAction() == MotionEvent.ACTION_DOWN) { 106 | mTouch.x = event.getX(); 107 | mTouch.y = event.getY(); 108 | // calcCornerXY(mTouch.x, mTouch.y); 109 | // this.postInvalidate(); 110 | } 111 | if (event.getAction() == MotionEvent.ACTION_UP) { 112 | if (canDragOver()) { 113 | startAnimation(1200); 114 | } else { 115 | mTouch.x = mCornerX - 0.09f; 116 | mTouch.y = mCornerY - 0.09f; 117 | } 118 | 119 | this.postInvalidate(); 120 | } 121 | // return super.onTouchEvent(event); 122 | return true; 123 | } 124 | 125 | /** 求解直线P1P2和直线P3P4的交点坐标 */ 126 | public PointF getCross(PointF P1, PointF P2, PointF P3, PointF P4) { 127 | PointF CrossP = new PointF(); 128 | // 二元函数通式: y=ax+b 129 | float a1 = (P2.y - P1.y) / (P2.x - P1.x); 130 | float b1 = ((P1.x * P2.y) - (P2.x * P1.y)) / (P1.x - P2.x); 131 | 132 | float a2 = (P4.y - P3.y) / (P4.x - P3.x); 133 | float b2 = ((P3.x * P4.y) - (P4.x * P3.y)) / (P3.x - P4.x); 134 | CrossP.x = (b2 - b1) / (a1 - a2); 135 | CrossP.y = a1 * CrossP.x + b1; 136 | return CrossP; 137 | } 138 | 139 | private void calcPoints() { 140 | mMiddleX = (mTouch.x + mCornerX) / 2; 141 | mMiddleY = (mTouch.y + mCornerY) / 2; 142 | mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY) * (mCornerY - mMiddleY) / (mCornerX - mMiddleX); 143 | mBezierControl1.y = mCornerY; 144 | mBezierControl2.x = mCornerX; 145 | mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY); 146 | 147 | mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x) / 2; 148 | mBezierStart1.y = mCornerY; 149 | 150 | // 当mBezierStart1.x < 0或者mBezierStart1.x > 480时 151 | // 如果继续翻页,会出现BUG故在此限制 152 | if (mTouch.x > 0 && mTouch.x < mWidth) { 153 | if (mBezierStart1.x < 0 || mBezierStart1.x > mWidth) { 154 | if (mBezierStart1.x < 0) 155 | mBezierStart1.x = mWidth - mBezierStart1.x; 156 | 157 | float f1 = Math.abs(mCornerX - mTouch.x); 158 | float f2 = mWidth * f1 / mBezierStart1.x; 159 | mTouch.x = Math.abs(mCornerX - f2); 160 | 161 | float f3 = Math.abs(mCornerX - mTouch.x) 162 | * Math.abs(mCornerY - mTouch.y) / f1; 163 | mTouch.y = Math.abs(mCornerY - f3); 164 | 165 | mMiddleX = (mTouch.x + mCornerX) / 2; 166 | mMiddleY = (mTouch.y + mCornerY) / 2; 167 | 168 | mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY) * (mCornerY - mMiddleY) / (mCornerX - mMiddleX); 169 | mBezierControl1.y = mCornerY; 170 | 171 | mBezierControl2.x = mCornerX; 172 | mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX) * (mCornerX - mMiddleX) / (mCornerY - mMiddleY); 173 | mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x) / 2; 174 | } 175 | } 176 | mBezierStart2.x = mCornerX; 177 | mBezierStart2.y = mBezierControl2.y - (mCornerY - mBezierControl2.y) / 2; 178 | 179 | mTouchToCornerDis = (float) Math.hypot((mTouch.x - mCornerX), (mTouch.y - mCornerY)); 180 | 181 | mBezierEnd1 = getCross(mTouch, mBezierControl1, mBezierStart1, mBezierStart2); 182 | mBezierEnd2 = getCross(mTouch, mBezierControl2, mBezierStart1, mBezierStart2); 183 | 184 | /* 185 | * mBeziervertex1.x 推导 186 | * ((mBezierStart1.x+mBezierEnd1.x)/2+mBezierControl1.x)/2 化简等价于 187 | * (mBezierStart1.x+ 2*mBezierControl1.x+mBezierEnd1.x) / 4 188 | */ 189 | mBeziervertex1.x = (mBezierStart1.x + 2 * mBezierControl1.x + mBezierEnd1.x) / 4; 190 | mBeziervertex1.y = (2 * mBezierControl1.y + mBezierStart1.y + mBezierEnd1.y) / 4; 191 | mBeziervertex2.x = (mBezierStart2.x + 2 * mBezierControl2.x + mBezierEnd2.x) / 4; 192 | mBeziervertex2.y = (2 * mBezierControl2.y + mBezierStart2.y + mBezierEnd2.y) / 4; 193 | } 194 | 195 | private void drawCurrentPageArea(Canvas canvas, Bitmap bitmap, Path path) { 196 | mPath0.reset(); 197 | mPath0.moveTo(mBezierStart1.x, mBezierStart1.y); 198 | mPath0.quadTo(mBezierControl1.x, mBezierControl1.y, mBezierEnd1.x, mBezierEnd1.y); 199 | mPath0.lineTo(mTouch.x, mTouch.y); 200 | mPath0.lineTo(mBezierEnd2.x, mBezierEnd2.y); 201 | mPath0.quadTo(mBezierControl2.x, mBezierControl2.y, mBezierStart2.x, mBezierStart2.y); 202 | mPath0.lineTo(mCornerX, mCornerY); 203 | mPath0.close(); 204 | 205 | canvas.save(); 206 | canvas.clipPath(path, Region.Op.XOR); 207 | canvas.drawBitmap(bitmap, 0, 0, null); 208 | canvas.restore(); 209 | } 210 | 211 | private void drawNextPageAreaAndShadow(Canvas canvas, Bitmap bitmap) { 212 | mPath1.reset(); 213 | mPath1.moveTo(mBezierStart1.x, mBezierStart1.y); 214 | mPath1.lineTo(mBeziervertex1.x, mBeziervertex1.y); 215 | mPath1.lineTo(mBeziervertex2.x, mBeziervertex2.y); 216 | mPath1.lineTo(mBezierStart2.x, mBezierStart2.y); 217 | mPath1.lineTo(mCornerX, mCornerY); 218 | mPath1.close(); 219 | 220 | mDegrees = (float) Math.toDegrees(Math.atan2(mBezierControl1.x - mCornerX, mBezierControl2.y - mCornerY)); 221 | int leftx; 222 | int rightx; 223 | GradientDrawable mBackShadowDrawable; 224 | if (mIsRTandLB) { 225 | leftx = (int) (mBezierStart1.x); 226 | rightx = (int) (mBezierStart1.x + mTouchToCornerDis / 4); 227 | mBackShadowDrawable = mBackShadowDrawableLR; 228 | } else { 229 | leftx = (int) (mBezierStart1.x - mTouchToCornerDis / 4); 230 | rightx = (int) mBezierStart1.x; 231 | mBackShadowDrawable = mBackShadowDrawableRL; 232 | } 233 | canvas.save(); 234 | canvas.clipPath(mPath0); 235 | canvas.clipPath(mPath1, Region.Op.INTERSECT); 236 | canvas.drawBitmap(bitmap, 0, 0, null); 237 | canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y); 238 | mBackShadowDrawable.setBounds(leftx, (int) mBezierStart1.y, rightx, (int) (mMaxLength + mBezierStart1.y)); 239 | mBackShadowDrawable.draw(canvas); 240 | canvas.restore(); 241 | } 242 | 243 | public void setBitmaps(Bitmap bm1, Bitmap bm2) { 244 | mCurPageBitmap = bm1; 245 | mNextPageBitmap = bm2; 246 | } 247 | 248 | public void setScreen(int w, int h) { 249 | mWidth = w; 250 | mHeight = h; 251 | } 252 | 253 | @Override 254 | protected void onDraw(Canvas canvas) { 255 | canvas.drawColor(0xFFAAAAAA); 256 | calcPoints(); 257 | drawCurrentPageArea(canvas, mCurPageBitmap, mPath0); 258 | drawNextPageAreaAndShadow(canvas, mNextPageBitmap); 259 | drawCurrentPageShadow(canvas); 260 | drawCurrentBackArea(canvas, mCurPageBitmap); 261 | } 262 | 263 | /** 创建阴影的GradientDrawable */ 264 | private void createDrawable() { 265 | int[] color = { 0x333333, 0xb0333333 }; 266 | mFolderShadowDrawableRL = new GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, color); 267 | mFolderShadowDrawableRL.setGradientType(GradientDrawable.LINEAR_GRADIENT); 268 | 269 | mFolderShadowDrawableLR = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, color); 270 | mFolderShadowDrawableLR.setGradientType(GradientDrawable.LINEAR_GRADIENT); 271 | 272 | mBackShadowColors = new int[] { 0xff111111, 0x111111 }; 273 | mBackShadowDrawableRL = new GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, mBackShadowColors); 274 | mBackShadowDrawableRL.setGradientType(GradientDrawable.LINEAR_GRADIENT); 275 | 276 | mBackShadowDrawableLR = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, mBackShadowColors); 277 | mBackShadowDrawableLR.setGradientType(GradientDrawable.LINEAR_GRADIENT); 278 | 279 | mFrontShadowColors = new int[] { 0x80111111, 0x111111 }; 280 | mFrontShadowDrawableVLR = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT, mFrontShadowColors); 281 | mFrontShadowDrawableVLR.setGradientType(GradientDrawable.LINEAR_GRADIENT); 282 | mFrontShadowDrawableVRL = new GradientDrawable(GradientDrawable.Orientation.RIGHT_LEFT, mFrontShadowColors); 283 | mFrontShadowDrawableVRL.setGradientType(GradientDrawable.LINEAR_GRADIENT); 284 | 285 | mFrontShadowDrawableHTB = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, mFrontShadowColors); 286 | mFrontShadowDrawableHTB.setGradientType(GradientDrawable.LINEAR_GRADIENT); 287 | 288 | mFrontShadowDrawableHBT = new GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, mFrontShadowColors); 289 | mFrontShadowDrawableHBT.setGradientType(GradientDrawable.LINEAR_GRADIENT); 290 | } 291 | 292 | /** 绘制翻起页的阴影 */ 293 | public void drawCurrentPageShadow(Canvas canvas) { 294 | double degree; 295 | if (mIsRTandLB) { 296 | degree = Math.PI / 4 - Math.atan2(mBezierControl1.y - mTouch.y, mTouch.x - mBezierControl1.x); 297 | } else { 298 | degree = Math.PI / 4 - Math.atan2(mTouch.y - mBezierControl1.y, mTouch.x - mBezierControl1.x); 299 | } 300 | // 翻起页阴影顶点与touch点的距离 301 | double d1 = (float) 25 * 1.414 * Math.cos(degree); 302 | double d2 = (float) 25 * 1.414 * Math.sin(degree); 303 | float x = (float) (mTouch.x + d1); 304 | float y; 305 | if (mIsRTandLB) { 306 | y = (float) (mTouch.y + d2); 307 | } else { 308 | y = (float) (mTouch.y - d2); 309 | } 310 | mPath1.reset(); 311 | mPath1.moveTo(x, y); 312 | mPath1.lineTo(mTouch.x, mTouch.y); 313 | mPath1.lineTo(mBezierControl1.x, mBezierControl1.y); 314 | mPath1.lineTo(mBezierStart1.x, mBezierStart1.y); 315 | mPath1.close(); 316 | float rotateDegrees; 317 | canvas.save(); 318 | 319 | canvas.clipPath(mPath0, Region.Op.XOR); 320 | canvas.clipPath(mPath1, Region.Op.INTERSECT); 321 | int leftx; 322 | int rightx; 323 | GradientDrawable mCurrentPageShadow; 324 | if (mIsRTandLB) { 325 | leftx = (int) (mBezierControl1.x); 326 | rightx = (int) mBezierControl1.x + 25; 327 | mCurrentPageShadow = mFrontShadowDrawableVLR; 328 | } else { 329 | leftx = (int) (mBezierControl1.x - 25); 330 | rightx = (int) mBezierControl1.x + 1; 331 | mCurrentPageShadow = mFrontShadowDrawableVRL; 332 | } 333 | 334 | rotateDegrees = (float) Math.toDegrees(Math.atan2(mTouch.x - mBezierControl1.x, mBezierControl1.y - mTouch.y)); 335 | canvas.rotate(rotateDegrees, mBezierControl1.x, mBezierControl1.y); 336 | mCurrentPageShadow.setBounds(leftx, (int) (mBezierControl1.y - mMaxLength), rightx, (int) (mBezierControl1.y)); 337 | mCurrentPageShadow.draw(canvas); 338 | canvas.restore(); 339 | 340 | mPath1.reset(); 341 | mPath1.moveTo(x, y); 342 | mPath1.lineTo(mTouch.x, mTouch.y); 343 | mPath1.lineTo(mBezierControl2.x, mBezierControl2.y); 344 | mPath1.lineTo(mBezierStart2.x, mBezierStart2.y); 345 | mPath1.close(); 346 | canvas.save(); 347 | canvas.clipPath(mPath0, Region.Op.XOR); 348 | canvas.clipPath(mPath1, Region.Op.INTERSECT); 349 | if (mIsRTandLB) { 350 | leftx = (int) (mBezierControl2.y); 351 | rightx = (int) (mBezierControl2.y + 25); 352 | mCurrentPageShadow = mFrontShadowDrawableHTB; 353 | } else { 354 | leftx = (int) (mBezierControl2.y - 25); 355 | rightx = (int) (mBezierControl2.y + 1); 356 | mCurrentPageShadow = mFrontShadowDrawableHBT; 357 | } 358 | rotateDegrees = (float) Math.toDegrees(Math.atan2(mBezierControl2.y - mTouch.y, mBezierControl2.x - mTouch.x)); 359 | canvas.rotate(rotateDegrees, mBezierControl2.x, mBezierControl2.y); 360 | float temp; 361 | if (mBezierControl2.y < 0) 362 | temp = mBezierControl2.y - mHeight; 363 | else 364 | temp = mBezierControl2.y; 365 | 366 | int hmg = (int) Math.hypot(mBezierControl2.x, temp); 367 | if (hmg > mMaxLength) 368 | mCurrentPageShadow.setBounds((int) (mBezierControl2.x - 25) - hmg, leftx, (int) (mBezierControl2.x + mMaxLength) - hmg, rightx); 369 | else 370 | mCurrentPageShadow.setBounds((int) (mBezierControl2.x - mMaxLength), leftx, (int) (mBezierControl2.x), rightx); 371 | 372 | mCurrentPageShadow.draw(canvas); 373 | canvas.restore(); 374 | } 375 | 376 | /** 绘制翻起页背面 */ 377 | private void drawCurrentBackArea(Canvas canvas, Bitmap bitmap) { 378 | int i = (int) (mBezierStart1.x + mBezierControl1.x) / 2; 379 | float f1 = Math.abs(i - mBezierControl1.x); 380 | int i1 = (int) (mBezierStart2.y + mBezierControl2.y) / 2; 381 | float f2 = Math.abs(i1 - mBezierControl2.y); 382 | float f3 = Math.min(f1, f2); 383 | mPath1.reset(); 384 | mPath1.moveTo(mBeziervertex2.x, mBeziervertex2.y); 385 | mPath1.lineTo(mBeziervertex1.x, mBeziervertex1.y); 386 | mPath1.lineTo(mBezierEnd1.x, mBezierEnd1.y); 387 | mPath1.lineTo(mTouch.x, mTouch.y); 388 | mPath1.lineTo(mBezierEnd2.x, mBezierEnd2.y); 389 | mPath1.close(); 390 | GradientDrawable mFolderShadowDrawable; 391 | int left; 392 | int right; 393 | if (mIsRTandLB) { 394 | left = (int) (mBezierStart1.x - 1); 395 | right = (int) (mBezierStart1.x + f3 + 1); 396 | mFolderShadowDrawable = mFolderShadowDrawableLR; 397 | } else { 398 | left = (int) (mBezierStart1.x - f3 - 1); 399 | right = (int) (mBezierStart1.x + 1); 400 | mFolderShadowDrawable = mFolderShadowDrawableRL; 401 | } 402 | canvas.save(); 403 | canvas.clipPath(mPath0); 404 | canvas.clipPath(mPath1, Region.Op.INTERSECT); 405 | 406 | mPaint.setColorFilter(mColorMatrixFilter); 407 | 408 | float dis = (float) Math.hypot(mCornerX - mBezierControl1.x, mBezierControl2.y - mCornerY); 409 | float f8 = (mCornerX - mBezierControl1.x) / dis; 410 | float f9 = (mBezierControl2.y - mCornerY) / dis; 411 | mMatrixArray[0] = 1 - 2 * f9 * f9; 412 | mMatrixArray[1] = 2 * f8 * f9; 413 | mMatrixArray[3] = mMatrixArray[1]; 414 | mMatrixArray[4] = 1 - 2 * f8 * f8; 415 | mMatrix.reset(); 416 | mMatrix.setValues(mMatrixArray); 417 | mMatrix.preTranslate(-mBezierControl1.x, -mBezierControl1.y); 418 | mMatrix.postTranslate(mBezierControl1.x, mBezierControl1.y); 419 | canvas.drawBitmap(bitmap, mMatrix, mPaint); 420 | //canvas.drawBitmap(bitmap, mMatrix, null); 421 | mPaint.setColorFilter(null); 422 | canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y); 423 | mFolderShadowDrawable.setBounds(left, (int) mBezierStart1.y, right, (int) (mBezierStart1.y + mMaxLength)); 424 | mFolderShadowDrawable.draw(canvas); 425 | canvas.restore(); 426 | } 427 | 428 | public void computeScroll() { 429 | super.computeScroll(); 430 | if (mScroller.computeScrollOffset()) { 431 | float x = mScroller.getCurrX(); 432 | float y = mScroller.getCurrY(); 433 | mTouch.x = x; 434 | mTouch.y = y; 435 | postInvalidate(); 436 | } 437 | } 438 | 439 | private void startAnimation(int delayMillis) { 440 | int dx, dy; // dx 水平方向滑动的距离,负值会使滚动向左滚动 dy 垂直方向滑动的距离,负值会使滚动向上滚动 441 | if (mCornerX > 0) { 442 | dx = -(int) (mWidth + mTouch.x); 443 | } else { 444 | dx = (int) (mWidth - mTouch.x + mWidth); 445 | } 446 | if (mCornerY > 0) { 447 | dy = (int) (mHeight - mTouch.y); 448 | } else { 449 | dy = (int) (1 - mTouch.y); // 防止mTouch.y最终变为0 450 | } 451 | mScroller.startScroll((int) mTouch.x, (int) mTouch.y, dx, dy, delayMillis); 452 | } 453 | 454 | public void abortAnimation() { 455 | if (!mScroller.isFinished()) { 456 | mScroller.abortAnimation(); 457 | } 458 | } 459 | 460 | public boolean canDragOver() { 461 | if (mTouchToCornerDis > mWidth / 10) 462 | return true; 463 | return false; 464 | } 465 | 466 | /** 是否从左边翻向右边 */ 467 | public boolean DragToRight() { 468 | if (mCornerX > 0) 469 | return false; 470 | return true; 471 | } 472 | 473 | } 474 | -------------------------------------------------------------------------------- /src/com/example/bezierCurve/PagerFactory.java: -------------------------------------------------------------------------------- 1 | package com.example.bezierCurve; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.Paint; 7 | import android.graphics.Paint.Align; 8 | 9 | 10 | public class PagerFactory { 11 | private Context mContext; 12 | private Bitmap m_book_bg = null; 13 | 14 | private int m_backColor = 0xffff9e85; // 背景颜色 15 | 16 | private boolean m_isfirstPage,m_islastPage; 17 | 18 | private Paint mPaint; 19 | 20 | public PagerFactory(Context context) { 21 | mContext = context; 22 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 23 | mPaint.setTextAlign(Align.LEFT); 24 | mPaint.setColor(m_backColor); 25 | } 26 | 27 | public void onDraw(Canvas c) { 28 | if (m_book_bg == null) 29 | c.drawColor(m_backColor); 30 | else 31 | c.drawBitmap(m_book_bg, 0, 0, null); 32 | } 33 | 34 | public void onDraw(Canvas c, Bitmap bitmap){ 35 | c.drawBitmap(bitmap, 0, 0, null); 36 | } 37 | 38 | 39 | public void setBgBitmap(Bitmap BG) { 40 | m_book_bg = BG; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /wiki/result.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skypanda100/BezierCurve/43bfd64ed2ebebbe16623f1af0978ed7339c33dd/wiki/result.gif --------------------------------------------------------------------------------