├── .classpath ├── .gitignore ├── .project ├── AndroidManifest.xml ├── README.md ├── proguard.cfg ├── project.properties ├── res ├── drawable-hdpi │ ├── bg_foot.png │ ├── bg_footbar.png │ ├── bg_title.png │ ├── btn_sx.png │ ├── btn_xr.png │ ├── dk.jpg │ ├── home_btn_bg_d.png │ ├── home_btn_bg_n.png │ ├── home_btn_bg_s.png │ ├── ic_launcher.png │ ├── ico_dp01.png │ ├── ico_gd01.png │ ├── ico_tt01.png │ ├── ico_zh01.png │ ├── ico_zy01.png │ ├── radio_bg.xml │ ├── shelf_bkg.png │ ├── storm.jpg │ └── top.gif ├── drawable-ldpi │ ├── ic_launcher.png │ └── text.png ├── drawable-mdpi │ ├── focused_application_background.9.png │ ├── ic_launcher.png │ ├── mainbg.jpg │ └── pressed_application_background.9.png ├── drawable │ ├── item_selector.xml │ ├── itemcolor.xml │ └── itemsize.xml ├── layout │ ├── main.xml │ ├── mainmenu.xml │ └── relative.xml ├── menu │ └── game_menu.xml └── values │ ├── arrays.xml │ ├── strings.xml │ └── styles.xml └── src └── com ├── ebook ├── EbookActivity.java ├── MainMenu.java ├── bookpage │ ├── BookPageFactory.java │ └── PageWidget.java └── scansd │ ├── BookMark.java │ └── ScanSD.java └── sqlite └── DbHelper.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | 15 | # Local configuration file (sdk path, etc) 16 | local.properties 17 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | ebook 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ebook 2 | ===== 3 | 4 | 使用赛贝尔曲线的电子书,可以随意翻卷 The first version, copy from http://www.eoeandroid.com/forum.php?mod=viewthread&tid=147987&extra=page%3D1&page=1 -------------------------------------------------------------------------------- /proguard.cfg: -------------------------------------------------------------------------------- 1 | -optimizationpasses 5 2 | -dontusemixedcaseclassnames 3 | -dontskipnonpubliclibraryclasses 4 | -dontpreverify 5 | -verbose 6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* 7 | 8 | -keep public class * extends android.app.Activity 9 | -keep public class * extends android.app.Application 10 | -keep public class * extends android.app.Service 11 | -keep public class * extends android.content.BroadcastReceiver 12 | -keep public class * extends android.content.ContentProvider 13 | -keep public class * extends android.app.backup.BackupAgentHelper 14 | -keep public class * extends android.preference.Preference 15 | -keep public class com.android.vending.licensing.ILicensingService 16 | 17 | -keepclasseswithmembernames class * { 18 | native ; 19 | } 20 | 21 | -keepclasseswithmembers class * { 22 | public (android.content.Context, android.util.AttributeSet); 23 | } 24 | 25 | -keepclasseswithmembers class * { 26 | public (android.content.Context, android.util.AttributeSet, int); 27 | } 28 | 29 | -keepclassmembers class * extends android.app.Activity { 30 | public void *(android.view.View); 31 | } 32 | 33 | -keepclassmembers enum * { 34 | public static **[] values(); 35 | public static ** valueOf(java.lang.String); 36 | } 37 | 38 | -keep class * implements android.os.Parcelable { 39 | public static final android.os.Parcelable$Creator *; 40 | } 41 | -------------------------------------------------------------------------------- /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 use, 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | 10 | # Project target. 11 | target=android-10 12 | -------------------------------------------------------------------------------- /res/drawable-hdpi/bg_foot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/bg_foot.png -------------------------------------------------------------------------------- /res/drawable-hdpi/bg_footbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/bg_footbar.png -------------------------------------------------------------------------------- /res/drawable-hdpi/bg_title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/bg_title.png -------------------------------------------------------------------------------- /res/drawable-hdpi/btn_sx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/btn_sx.png -------------------------------------------------------------------------------- /res/drawable-hdpi/btn_xr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/btn_xr.png -------------------------------------------------------------------------------- /res/drawable-hdpi/dk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/dk.jpg -------------------------------------------------------------------------------- /res/drawable-hdpi/home_btn_bg_d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/home_btn_bg_d.png -------------------------------------------------------------------------------- /res/drawable-hdpi/home_btn_bg_n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/home_btn_bg_n.png -------------------------------------------------------------------------------- /res/drawable-hdpi/home_btn_bg_s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/home_btn_bg_s.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ico_dp01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/ico_dp01.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ico_gd01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/ico_gd01.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ico_tt01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/ico_tt01.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ico_zh01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/ico_zh01.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ico_zy01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/ico_zy01.png -------------------------------------------------------------------------------- /res/drawable-hdpi/radio_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /res/drawable-hdpi/shelf_bkg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/shelf_bkg.png -------------------------------------------------------------------------------- /res/drawable-hdpi/storm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/storm.jpg -------------------------------------------------------------------------------- /res/drawable-hdpi/top.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-hdpi/top.gif -------------------------------------------------------------------------------- /res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-ldpi/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-ldpi/text.png -------------------------------------------------------------------------------- /res/drawable-mdpi/focused_application_background.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-mdpi/focused_application_background.9.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/mainbg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-mdpi/mainbg.jpg -------------------------------------------------------------------------------- /res/drawable-mdpi/pressed_application_background.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/watermelon/ebook/ae22b34035bd8e8e2e9c2bb36ab2353f8d62dbc5/res/drawable-mdpi/pressed_application_background.9.png -------------------------------------------------------------------------------- /res/drawable/item_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 9 | 10 | -------------------------------------------------------------------------------- /res/drawable/itemcolor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /res/drawable/itemsize.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | 23 | 24 | 31 | 32 | 39 | 40 | 41 | 49 | 50 | 55 | 56 | 60 | 61 | 66 | 67 | 73 | 74 | 81 | 82 | 88 | 89 | 95 | 96 | 102 | 103 | 109 | 110 | 111 | 112 | 113 | 114 | 121 | 122 | 126 | 127 | 133 | 134 | 139 | 140 | 146 | 147 | 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /res/layout/mainmenu.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 15 | 16 | 23 | 24 | 31 | 32 | 39 | 40 | 41 | 49 | 50 | 55 | 56 | 60 | 61 | 66 | 67 | 73 | 74 | 81 | 82 | 88 | 89 | 95 | 96 | 102 | 103 | 109 | 110 | 111 | 112 | 113 | 114 | 121 | 122 | 126 | 127 | 133 | 134 | 139 | 140 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /res/layout/relative.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 19 | -------------------------------------------------------------------------------- /res/menu/game_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | -------------------------------------------------------------------------------- /res/values/arrays.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 书签1 5 | 书签2 6 | 书签3 7 | 书签4 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Hello World, EbookActivity! 5 | Ebook 6 | 书签 7 | 保存 8 | 打开 9 | 10 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 17 | -------------------------------------------------------------------------------- /src/com/ebook/EbookActivity.java: -------------------------------------------------------------------------------- 1 | package com.ebook; 2 | 3 | import java.io.IOException; 4 | 5 | import android.app.Activity; 6 | import android.app.AlertDialog; 7 | import android.app.Dialog; 8 | import android.content.Context; 9 | import android.content.DialogInterface; 10 | import android.content.Intent; 11 | import android.database.Cursor; 12 | import android.graphics.Bitmap; 13 | import android.graphics.BitmapFactory; 14 | import android.graphics.Canvas; 15 | import android.graphics.Color; 16 | import android.os.Bundle; 17 | import android.os.Handler; 18 | import android.os.Message; 19 | import android.util.DisplayMetrics; 20 | import android.util.Log; 21 | import android.view.Menu; 22 | import android.view.MenuItem; 23 | import android.view.MotionEvent; 24 | import android.view.View; 25 | import android.view.View.OnTouchListener; 26 | import android.view.Window; 27 | import android.view.WindowManager; 28 | import android.widget.Toast; 29 | 30 | import com.ebook.bookpage.BookPageFactory; 31 | import com.ebook.bookpage.PageWidget; 32 | import com.sqlite.DbHelper; 33 | 34 | public class EbookActivity extends Activity { 35 | 36 | public final static int OPENMARK = 0; 37 | public final static int SAVEMARK = 1; 38 | public final static int TEXTSET = 2; 39 | 40 | private PageWidget mPageWidget; 41 | private BookPageFactory pagefactory; 42 | DbHelper db; 43 | Bitmap mCurPageBitmap, mNextPageBitmap; 44 | Canvas mCurPageCanvas, mNextPageCanvas; 45 | Context mContext; 46 | Cursor mCursor; 47 | final String[] items = { "书签1 未使用", "书签2 未使用", "书签3 未使用", "书签4 未使用", "自动书签 未使用" }; 48 | String fileName; 49 | String path; 50 | int curPostion; 51 | int screenWidth; 52 | int screenHeight; 53 | int bookMarkPos; 54 | 55 | /** Called when the activity is first created. */ 56 | @Override 57 | public void onCreate(Bundle savedInstanceState) { 58 | super.onCreate(savedInstanceState); 59 | requestWindowFeature(Window.FEATURE_NO_TITLE); 60 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 61 | WindowManager.LayoutParams.FLAG_FULLSCREEN); 62 | 63 | initScreedWH(); 64 | mPageWidget = new PageWidget(this); 65 | mPageWidget.setWidth(screenWidth); 66 | mPageWidget.setHeight(screenHeight); 67 | mContext = this; 68 | 69 | initBookMark(); 70 | 71 | setContentView(mPageWidget); 72 | 73 | initBookPage(); 74 | 75 | String pos = this.getIntent().getStringExtra("pos"); 76 | 77 | if (!isViewIntent()) { 78 | path = this.getIntent().getStringExtra("pathes"); 79 | 80 | } else { 81 | path = this.getIntent().getData().getPath(); 82 | } 83 | 84 | try { 85 | Log.i("path", path); 86 | pagefactory.openBook(path); 87 | fileName = pagefactory.getFileName(); 88 | if (pos != null) { 89 | pagefactory.setBeginPos(Integer.valueOf(pos)); 90 | pagefactory.pageUp(); 91 | } 92 | pagefactory.onDraw(mCurPageCanvas); 93 | } catch (IOException e1) { 94 | Toast.makeText(this, fileName + "不存在,请将文件放在SD卡根目录下,可以超过100M容量", 95 | Toast.LENGTH_LONG).show(); 96 | } 97 | 98 | mPageWidget.setBitmaps(mCurPageBitmap, mCurPageBitmap); 99 | 100 | mPageWidget.setOnTouchListener(new OnTouchListener() { 101 | public boolean onTouch(View v, MotionEvent e) { 102 | // TODO Auto-generated method stub 103 | boolean ret = false; 104 | if (v == mPageWidget) { 105 | if (e.getAction() == MotionEvent.ACTION_DOWN) { 106 | mPageWidget.abortAnimation(); 107 | mPageWidget.calcCornerXY(e.getX(), e.getY()); 108 | pagefactory.onDraw(mCurPageCanvas); 109 | if (mPageWidget.DragToRight()) { 110 | try { 111 | pagefactory.prePage(); 112 | } catch (IOException e1) { 113 | e1.printStackTrace(); 114 | } 115 | if (pagefactory.isFirstPage()) 116 | return false; 117 | pagefactory.onDraw(mNextPageCanvas); 118 | } else { 119 | try { 120 | pagefactory.nextPage(); 121 | } catch (IOException e1) { 122 | e1.printStackTrace(); 123 | } 124 | if (pagefactory.isLastPage()) { 125 | return false; 126 | } 127 | pagefactory.onDraw(mNextPageCanvas); 128 | } 129 | mPageWidget.setBitmaps(mCurPageBitmap, mNextPageBitmap); 130 | } 131 | ret = mPageWidget.doTouchEvent(e); 132 | 133 | return ret; 134 | } 135 | return false; 136 | } 137 | }); 138 | } 139 | 140 | private void initScreedWH() { 141 | DisplayMetrics dm = new DisplayMetrics(); 142 | getWindowManager().getDefaultDisplay().getMetrics(dm); 143 | screenHeight = dm.heightPixels; 144 | screenWidth = dm.widthPixels; 145 | } 146 | 147 | private boolean isViewIntent() { 148 | String action = getIntent().getAction(); 149 | return Intent.ACTION_VIEW.equals(action); 150 | } 151 | 152 | private void initBookPage() { 153 | mCurPageBitmap = Bitmap.createBitmap(screenWidth, screenHeight, 154 | Bitmap.Config.ARGB_8888); 155 | mNextPageBitmap = Bitmap.createBitmap(screenWidth, screenHeight, 156 | Bitmap.Config.ARGB_8888); 157 | 158 | mCurPageCanvas = new Canvas(mCurPageBitmap); 159 | mNextPageCanvas = new Canvas(mNextPageBitmap); 160 | pagefactory = new BookPageFactory(screenWidth, screenHeight); 161 | 162 | pagefactory.setBgBitmap(BitmapFactory.decodeResource( 163 | mContext.getResources(), R.drawable.shelf_bkg)); 164 | } 165 | 166 | private void initBookMark() { 167 | db = new DbHelper(mContext); 168 | try { 169 | mCursor = db.select(); 170 | 171 | } catch (Exception e) { 172 | e.printStackTrace(); 173 | } 174 | if (mCursor.getCount() > 0) { 175 | for (int i = 0; i < mCursor.getCount(); i++) { 176 | mCursor.moveToPosition(mCursor.getCount() - (i + 1)); 177 | String str = mCursor.getString(1); 178 | str = str.substring(str.lastIndexOf('/') + 1, str.length()); 179 | items[i] = str + ": " + mCursor.getString(2); 180 | } 181 | } 182 | db.close(); 183 | } 184 | 185 | public boolean onCreateOptionsMenu(Menu menu) { 186 | menu.add(0, 1, 1, fileName); 187 | menu.add(0, 2, 2, "书签"); 188 | menu.add(0, 3, 3, "设置"); 189 | menu.add(0, 4, 4, "退出"); 190 | return super.onCreateOptionsMenu(menu); 191 | } 192 | 193 | public boolean onOptionsItemSelected(MenuItem item) { 194 | switch (item.getItemId()) { 195 | case 1: 196 | Toast.makeText(this, "您正在观看: " + fileName, Toast.LENGTH_SHORT) 197 | .show(); 198 | return true; 199 | case 2: 200 | showDialog(OPENMARK); 201 | return true; 202 | 203 | case 3: 204 | showDialog(TEXTSET); 205 | break; 206 | 207 | case 4: 208 | finish(); 209 | default: 210 | break; 211 | } 212 | return super.onOptionsItemSelected(item); 213 | } 214 | 215 | protected Dialog onCreateDialog(int id) { 216 | switch (id) { 217 | case OPENMARK: 218 | return new AlertDialog.Builder(mContext) 219 | .setTitle(R.string.bookmark) 220 | 221 | .setSingleChoiceItems(items, 0, 222 | new DialogInterface.OnClickListener() { 223 | public void onClick(DialogInterface dialog, 224 | int which) { 225 | bookMarkPos = which; 226 | } 227 | }) 228 | .setPositiveButton(R.string.load_bookmark, 229 | new DialogInterface.OnClickListener() { 230 | public void onClick(DialogInterface dialog, 231 | int which) { 232 | Message msg = new Message(); 233 | msg.what = OPENMARK; 234 | msg.arg1 = bookMarkPos; 235 | mhHandler.sendMessage(msg); 236 | } 237 | }) 238 | .setNegativeButton(R.string.save_bookmark, 239 | new DialogInterface.OnClickListener() { 240 | public void onClick(DialogInterface dialog, 241 | int which) { 242 | Message msg = new Message(); 243 | msg.what = SAVEMARK; 244 | msg.arg1 = bookMarkPos; 245 | curPostion = pagefactory.getCurPostion(); 246 | msg.arg2 = curPostion; 247 | mhHandler.sendMessage(msg); 248 | } 249 | }).create(); 250 | case TEXTSET: 251 | String color[] = new String[] { "红色", "深灰色", "黄色", "蓝色", "黑色" }; 252 | return new AlertDialog.Builder(mContext) 253 | .setTitle("字体颜色设置") 254 | .setSingleChoiceItems(color, 0, 255 | new DialogInterface.OnClickListener() { 256 | public void onClick(DialogInterface dialog, 257 | int which) { 258 | bookMarkPos = which; 259 | } 260 | }) 261 | .setPositiveButton("ok", 262 | new DialogInterface.OnClickListener() { 263 | public void onClick(DialogInterface dialog, 264 | int which) { 265 | Message msg = new Message(); 266 | msg.what = TEXTSET; 267 | switch (bookMarkPos) { 268 | case 0: 269 | msg.arg1 = Color.RED; 270 | break; 271 | case 1: 272 | msg.arg1 = Color.DKGRAY; 273 | break; 274 | case 2: 275 | msg.arg1 = Color.YELLOW; 276 | break; 277 | case 3: 278 | msg.arg1 = Color.BLUE; 279 | break; 280 | case 4: 281 | msg.arg1 = Color.BLACK; 282 | break; 283 | 284 | default: 285 | break; 286 | } 287 | mhHandler.sendMessage(msg); 288 | } 289 | }) 290 | .setNegativeButton("cancle", 291 | new DialogInterface.OnClickListener() { 292 | public void onClick(DialogInterface dialog, 293 | int which) { 294 | } 295 | }).create(); 296 | default: 297 | break; 298 | } 299 | return null; 300 | 301 | } 302 | 303 | Handler mhHandler = new Handler() { 304 | public void handleMessage(Message msg) { 305 | switch (msg.what) { 306 | 307 | case TEXTSET: 308 | pagefactory.changBackGround(msg.arg1); 309 | pagefactory.onDraw(mCurPageCanvas); 310 | mPageWidget.postInvalidate(); 311 | break; 312 | 313 | case OPENMARK: 314 | try { 315 | mCursor = db.select(); 316 | 317 | } catch (Exception e) { 318 | e.printStackTrace(); 319 | } 320 | if (mCursor.getCount() > 0) { 321 | mCursor.moveToPosition(mCursor.getCount() - (msg.arg1 + 1)); 322 | String pos = mCursor.getString(2); 323 | String tmp = mCursor.getString(1); 324 | 325 | if (fileName.equals(tmp.substring(tmp.lastIndexOf('/') + 1, 326 | tmp.length()))) { 327 | 328 | pagefactory.setBeginPos(Integer.valueOf(pos)); 329 | try { 330 | pagefactory.prePage(); 331 | } catch (IOException e) { 332 | // TODO Auto-generated catch block 333 | e.printStackTrace(); 334 | } 335 | pagefactory.onDraw(mNextPageCanvas); 336 | mPageWidget.setBitmaps(mCurPageBitmap, mNextPageBitmap); 337 | mPageWidget.invalidate(); 338 | db.close(); 339 | } else { 340 | Intent intent = new Intent(EbookActivity.this, 341 | EbookActivity.class); 342 | intent.putExtra("pathes", mCursor.getString(1)); 343 | intent.putExtra("pos", mCursor.getString(2)); 344 | db.close(); 345 | startActivity(intent); 346 | finish(); 347 | } 348 | } 349 | break; 350 | 351 | case SAVEMARK: 352 | try { 353 | mCursor = db.select(); 354 | } catch (Exception e) { 355 | e.printStackTrace(); 356 | } 357 | if (mCursor.getCount() > 0 && mCursor.getCount() > msg.arg1) { 358 | mCursor.moveToPosition(mCursor.getCount() - (msg.arg1 + 1)); 359 | db.update(mCursor.getInt(0), path, String.valueOf(msg.arg2)); 360 | } else { 361 | db.insert(path, String.valueOf(msg.arg2)); 362 | } 363 | db.close(); 364 | items[msg.arg1] = path.substring(path.lastIndexOf('/') + 1, 365 | path.length()) + ": " + String.valueOf(msg.arg2); 366 | break; 367 | 368 | default: 369 | break; 370 | } 371 | super.handleMessage(msg); 372 | } 373 | }; 374 | } -------------------------------------------------------------------------------- /src/com/ebook/MainMenu.java: -------------------------------------------------------------------------------- 1 | package com.ebook; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | 7 | import android.app.Activity; 8 | import android.app.AlertDialog; 9 | import android.app.Dialog; 10 | import android.content.Context; 11 | import android.content.DialogInterface; 12 | import android.content.Intent; 13 | import android.database.Cursor; 14 | import android.os.Bundle; 15 | import android.os.Handler; 16 | import android.os.Message; 17 | import android.util.Log; 18 | import android.view.View; 19 | import android.view.View.OnClickListener; 20 | import android.view.Window; 21 | import android.view.WindowManager; 22 | import android.widget.AdapterView; 23 | import android.widget.AdapterView.OnItemClickListener; 24 | import android.widget.ImageView; 25 | import android.widget.ListView; 26 | import android.widget.RadioButton; 27 | import android.widget.SimpleAdapter; 28 | import android.widget.TextView; 29 | import android.widget.Toast; 30 | 31 | import com.ebook.scansd.ScanSD; 32 | import com.sqlite.DbHelper; 33 | 34 | public class MainMenu extends Activity { 35 | 36 | public final static int OPENMARK = 0; 37 | ScanSD scanSD; 38 | Intent intent; 39 | Context mContext; 40 | RadioButton nextPage; 41 | RadioButton bmRadioButton; 42 | ListView ListView; 43 | TextView textView; 44 | ImageView storm; 45 | private DbHelper db; 46 | private int pos; 47 | final String[] items = { "书签1 未使用", "书签2 未使用", "书签3 未使用", "书签4 未使用", "自动书签 未使用" }; 48 | Cursor mCursor; 49 | 50 | /** Called when the activity is first created. */ 51 | public void onCreate(Bundle savedInstanceState) { 52 | super.onCreate(savedInstanceState); 53 | requestWindowFeature(Window.FEATURE_NO_TITLE); 54 | getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 55 | WindowManager.LayoutParams.FLAG_FULLSCREEN); 56 | setContentView(R.layout.mainmenu); 57 | intent = new Intent(); 58 | mContext = this; 59 | 60 | scanSD = new ScanSD(); 61 | 62 | findView(); 63 | initBookMark(); 64 | initListView(); 65 | textView.setOnClickListener(radButtonClicked); 66 | nextPage.setOnClickListener(radButtonClicked); 67 | bmRadioButton.setOnClickListener(radButtonClicked); 68 | } 69 | 70 | private void findView() { 71 | textView = (TextView) findViewById(R.id.textView1); 72 | bmRadioButton = (RadioButton) findViewById(R.id.bookmark); 73 | storm = (ImageView) findViewById(R.id.storm); 74 | nextPage = (RadioButton) findViewById(R.id.radio_next); 75 | ListView = (ListView) findViewById(R.id.listfile); 76 | } 77 | 78 | private OnClickListener radButtonClicked = new OnClickListener() { 79 | 80 | @Override 81 | public void onClick(View view) { 82 | // TODO Auto-generated method stub 83 | switch (view.getId()) { 84 | case R.id.bookmark: 85 | showDialog(0); 86 | break; 87 | 88 | case R.id.radio_next: 89 | if (nextPage.getText().equals("下一页")) { 90 | nextPage.setText("上一页"); 91 | } else { 92 | nextPage.setText("下一页"); 93 | } 94 | break; 95 | case R.id.textView1: 96 | Toast.makeText(MainMenu.this, "thanks", 500).show(); 97 | finish(); 98 | break; 99 | } 100 | } 101 | }; 102 | 103 | private void initBookMark() { 104 | db = new DbHelper(mContext); 105 | try { 106 | mCursor = db.select(); 107 | } catch (Exception e) { 108 | e.printStackTrace(); 109 | } 110 | if (mCursor.getCount() > 0) { 111 | for (int i = 0; i < mCursor.getCount(); i++) { 112 | mCursor.moveToPosition(mCursor.getCount() - (i + 1)); 113 | String str = mCursor.getString(1); 114 | str = str.substring(str.lastIndexOf('/') + 1, str.length()); 115 | items[i] = str + ": " + mCursor.getString(2); 116 | } 117 | } 118 | db.close(); 119 | } 120 | 121 | private void initListView() { 122 | ArrayList list = new ArrayList(); 123 | list = scanSD.getFileList(); 124 | 125 | final SimpleAdapter adapter = new SimpleAdapter(this, 126 | scanSD.getMapData(list), R.layout.relative, 127 | new String[] { "ItemName" }, new int[] { R.id.ItemText }); 128 | 129 | ListView.setAdapter(adapter); 130 | ListView.setSelector(R.drawable.item_selector); 131 | ListView.setOnItemClickListener(new OnItemClickListener() { 132 | public void onItemClick(AdapterView arg0, View view, int pos, 133 | long id) { 134 | String path; 135 | @SuppressWarnings("unchecked") 136 | HashMap map = (HashMap) ListView 137 | .getItemAtPosition(pos); 138 | // String name = map.get("ItemText"); 139 | path = map.get("ItemPath"); 140 | 141 | intent.setClass(mContext, EbookActivity.class); 142 | intent.putExtra("pathes", path); 143 | startActivity(intent); 144 | adapter.notifyDataSetChanged(); // 通知adapter刷新数据 145 | } 146 | }); 147 | } 148 | 149 | protected Dialog onCreateDialog(int id) { 150 | return new AlertDialog.Builder(mContext) 151 | .setTitle(R.string.bookmark) 152 | 153 | .setSingleChoiceItems(items, 0, 154 | new DialogInterface.OnClickListener() { 155 | public void onClick(DialogInterface dialog, 156 | int which) { 157 | pos = which; 158 | } 159 | }) 160 | .setPositiveButton("取消", new DialogInterface.OnClickListener() { 161 | public void onClick(DialogInterface dialog, int which) { 162 | } 163 | }) 164 | .setNegativeButton(R.string.load_bookmark, 165 | new DialogInterface.OnClickListener() { 166 | public void onClick(DialogInterface dialog, 167 | int which) { 168 | Message msg = new Message(); 169 | msg.what = 0; 170 | msg.arg1 = pos; 171 | mhHandler.sendMessage(msg); 172 | } 173 | }).create(); 174 | } 175 | 176 | Handler mhHandler = new Handler() { 177 | public void handleMessage(Message msg) { 178 | switch (msg.what) { 179 | case OPENMARK: 180 | try { 181 | mCursor = db.select(); 182 | } catch (Exception e) { 183 | e.printStackTrace(); 184 | } 185 | if (mCursor.getCount() > 0) { 186 | mCursor.moveToPosition(mCursor.getCount() - (msg.arg1 + 1)); 187 | Log.i("string", items[mCursor.getCount() - (msg.arg1 + 1)]); 188 | intent.setClass(mContext, EbookActivity.class); 189 | intent.putExtra("pathes", mCursor.getString(1)); 190 | intent.putExtra("pos", mCursor.getString(2)); 191 | startActivity(intent); 192 | } 193 | db.close();// 打开之后记得关闭数据库 194 | break; 195 | 196 | default: 197 | break; 198 | } 199 | super.handleMessage(msg); 200 | } 201 | }; 202 | } -------------------------------------------------------------------------------- /src/com/ebook/bookpage/BookPageFactory.java: -------------------------------------------------------------------------------- 1 | package com.ebook.bookpage; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.RandomAccessFile; 6 | import java.io.UnsupportedEncodingException; 7 | import java.nio.MappedByteBuffer; 8 | import java.nio.channels.FileChannel; 9 | import java.text.DecimalFormat; 10 | import java.util.Vector; 11 | 12 | import android.graphics.Bitmap; 13 | import android.graphics.Canvas; 14 | import android.graphics.Color; 15 | import android.graphics.Paint; 16 | import android.graphics.Paint.Align; 17 | 18 | public class BookPageFactory { 19 | 20 | private File book_file = null; 21 | private MappedByteBuffer m_mbBuf = null; 22 | private int m_mbBufLen = 0;// 总长度 23 | private int m_mbBufBegin = 0;// 当前长度 24 | private int m_mbBufEnd = 0; 25 | private String m_strCharsetName = "GBK"; 26 | private Bitmap m_book_bg = null; 27 | private int mWidth; 28 | private int mHeight; 29 | 30 | private String fileName; 31 | 32 | private Vector m_lines = new Vector(); 33 | 34 | private int m_fontSize = 24; 35 | private int m_textColor = Color.BLACK; 36 | private int m_backColor = 0xffff9e85; // 背景颜色 37 | private int marginWidth = 15; // 左右与边缘的距离 38 | private int marginHeight = 20; // 上下与边缘的距离 39 | 40 | private int mLineCount; // 每页可以显示的行数 41 | private float mVisibleHeight; // 绘制内容的宽 42 | private float mVisibleWidth; // 绘制内容的 43 | private boolean m_isfirstPage, m_islastPage; 44 | 45 | private Paint mPaint; 46 | 47 | // 进度格式 48 | DecimalFormat df = new DecimalFormat("##.##"); 49 | 50 | public BookPageFactory(int w, int h) { 51 | mWidth = w; 52 | mHeight = h; 53 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 54 | mPaint.setTextAlign(Align.LEFT); 55 | mPaint.setTextSize(m_fontSize); 56 | mPaint.setColor(m_textColor); 57 | mVisibleWidth = mWidth - marginWidth * 2; 58 | mVisibleHeight = mHeight - marginHeight * 2; 59 | mLineCount = (int) (mVisibleHeight / m_fontSize); // 可显示的行数 60 | } 61 | 62 | public void openBook(String strFilePath) throws IOException { 63 | book_file = new File(strFilePath); 64 | long lLen = book_file.length(); 65 | m_mbBufLen = (int) lLen; 66 | fileName = book_file.getName(); 67 | m_mbBuf = new RandomAccessFile(book_file, "r").getChannel().map( 68 | FileChannel.MapMode.READ_ONLY, 0, lLen); 69 | } 70 | 71 | // 读取上一段落 72 | protected byte[] readParagraphBack(int nFromPos) { 73 | int nEnd = nFromPos; 74 | int i; 75 | byte b0, b1; 76 | if (m_strCharsetName.equals("UTF-16LE")) { 77 | i = nEnd - 2; 78 | while (i > 0) { 79 | b0 = m_mbBuf.get(i); 80 | b1 = m_mbBuf.get(i + 1); 81 | if (b0 == 0x0a && b1 == 0x00 && i != nEnd - 2) { 82 | i += 2; 83 | break; 84 | } 85 | i--; 86 | } 87 | 88 | } else if (m_strCharsetName.equals("UTF-16BE")) { 89 | i = nEnd - 2; 90 | while (i > 0) { 91 | b0 = m_mbBuf.get(i); 92 | b1 = m_mbBuf.get(i + 1); 93 | if (b0 == 0x00 && b1 == 0x0a && i != nEnd - 2) { 94 | i += 2; 95 | break; 96 | } 97 | i--; 98 | } 99 | } else { 100 | i = nEnd - 1; 101 | while (i > 0) { 102 | b0 = m_mbBuf.get(i); 103 | if (b0 == 0x0a && i != nEnd - 1) { 104 | i++; 105 | break; 106 | } 107 | i--; 108 | } 109 | } 110 | if (i < 0) 111 | i = 0; 112 | int nParaSize = nEnd - i; 113 | int j; 114 | byte[] buf = new byte[nParaSize]; 115 | for (j = 0; j < nParaSize; j++) { 116 | buf[j] = m_mbBuf.get(i + j); 117 | } 118 | return buf; 119 | } 120 | 121 | // 读取下一段落 122 | protected byte[] readParagraphForward(int nFromPos) { 123 | int nStart = nFromPos; 124 | int i = nStart; 125 | byte b0, b1; 126 | // 根据编码格式判断换行 127 | if (m_strCharsetName.equals("UTF-16LE")) { 128 | while (i < m_mbBufLen - 1) { 129 | b0 = m_mbBuf.get(i++); 130 | b1 = m_mbBuf.get(i++); 131 | if (b0 == 0x0a && b1 == 0x00) { 132 | break; 133 | } 134 | } 135 | } else if (m_strCharsetName.equals("UTF-16BE")) { 136 | while (i < m_mbBufLen - 1) { 137 | b0 = m_mbBuf.get(i++); 138 | b1 = m_mbBuf.get(i++); 139 | if (b0 == 0x00 && b1 == 0x0a) { 140 | break; 141 | } 142 | } 143 | } else { 144 | while (i < m_mbBufLen) { 145 | b0 = m_mbBuf.get(i++); 146 | if (b0 == 0x0a) { 147 | break; 148 | } 149 | } 150 | } 151 | int nParaSize = i - nStart; 152 | byte[] buf = new byte[nParaSize]; 153 | for (i = 0; i < nParaSize; i++) { 154 | buf[i] = m_mbBuf.get(nFromPos + i); 155 | } 156 | return buf; 157 | } 158 | 159 | protected Vector pageDown() { 160 | String strParagraph = ""; 161 | Vector lines = new Vector(); 162 | while (lines.size() < mLineCount && m_mbBufEnd < m_mbBufLen) { 163 | byte[] paraBuf = readParagraphForward(m_mbBufEnd); // 读取一个段落 164 | m_mbBufEnd += paraBuf.length; 165 | try { 166 | strParagraph = new String(paraBuf, m_strCharsetName); 167 | } catch (UnsupportedEncodingException e) { 168 | // TODO Auto-generated catch block 169 | e.printStackTrace(); 170 | } 171 | String strReturn = ""; 172 | if (strParagraph.indexOf("\r\n") != -1) { 173 | strReturn = "\r\n"; 174 | strParagraph = strParagraph.replaceAll("\r\n", ""); 175 | } else if (strParagraph.indexOf("\n") != -1) { 176 | strReturn = "\n"; 177 | strParagraph = strParagraph.replaceAll("\n", ""); 178 | } 179 | 180 | if (strParagraph.length() == 0) { 181 | lines.add(strParagraph); 182 | } 183 | while (strParagraph.length() > 0) { 184 | int nSize = mPaint.breakText(strParagraph, true, mVisibleWidth, 185 | null); 186 | lines.add(strParagraph.substring(0, nSize)); 187 | strParagraph = strParagraph.substring(nSize); 188 | if (lines.size() >= mLineCount) { 189 | break; 190 | } 191 | } 192 | if (strParagraph.length() != 0) { 193 | try { 194 | m_mbBufEnd -= (strParagraph + strReturn) 195 | .getBytes(m_strCharsetName).length; 196 | } catch (UnsupportedEncodingException e) { 197 | // TODO Auto-generated catch block 198 | e.printStackTrace(); 199 | } 200 | } 201 | } 202 | return lines; 203 | } 204 | 205 | public Vector pageUp() { 206 | if (m_mbBufBegin < 0) { 207 | m_mbBufBegin = 0; 208 | } 209 | Vector lines = new Vector(); 210 | String strParagraph = ""; 211 | while (lines.size() < mLineCount && m_mbBufBegin > 0) { 212 | Vector paraLines = new Vector(); 213 | byte[] paraBuf = readParagraphBack(m_mbBufBegin); 214 | m_mbBufBegin -= paraBuf.length; 215 | try { 216 | strParagraph = new String(paraBuf, m_strCharsetName); 217 | } catch (UnsupportedEncodingException e) { 218 | // TODO Auto-generated catch block 219 | e.printStackTrace(); 220 | } 221 | strParagraph = strParagraph.replaceAll("\r\n", ""); 222 | strParagraph = strParagraph.replaceAll("\n", ""); 223 | 224 | if (strParagraph.length() == 0) { 225 | paraLines.add(strParagraph); 226 | } 227 | while (strParagraph.length() > 0) { 228 | int nSize = mPaint.breakText(strParagraph, true, mVisibleWidth, 229 | null); 230 | paraLines.add(strParagraph.substring(0, nSize)); 231 | strParagraph = strParagraph.substring(nSize); 232 | } 233 | lines.addAll(0, paraLines); 234 | } 235 | while (lines.size() > mLineCount) { 236 | try { 237 | m_mbBufBegin += lines.get(0).getBytes(m_strCharsetName).length; 238 | lines.remove(0); 239 | } catch (UnsupportedEncodingException e) { 240 | // TODO Auto-generated catch block 241 | e.printStackTrace(); 242 | } 243 | } 244 | m_mbBufEnd = m_mbBufBegin; 245 | 246 | return lines; 247 | } 248 | 249 | public void prePage() throws IOException { 250 | if (m_mbBufBegin <= 0) { 251 | m_mbBufBegin = 0; 252 | m_isfirstPage = true; 253 | return; 254 | } else { 255 | m_isfirstPage = false; 256 | } 257 | m_lines.clear(); 258 | pageUp(); 259 | m_lines = pageDown(); 260 | } 261 | 262 | public void nextPage() throws IOException { 263 | if (m_mbBufEnd >= m_mbBufLen) { 264 | m_islastPage = true; 265 | return; 266 | } else { 267 | m_islastPage = false; 268 | } 269 | m_lines.clear(); 270 | m_mbBufBegin = m_mbBufEnd; 271 | m_lines = pageDown(); 272 | } 273 | 274 | public void onDraw(Canvas c) { 275 | if (m_lines.size() == 0) { 276 | m_lines = pageDown(); 277 | } 278 | if (m_lines.size() > 0) { 279 | if (m_book_bg == null) 280 | c.drawColor(m_backColor); 281 | else 282 | c.drawBitmap(m_book_bg, 0, 0, null); 283 | int y = marginHeight; 284 | for (String strLine : m_lines) { 285 | y += m_fontSize; 286 | c.drawText(strLine, marginWidth, y, mPaint); 287 | } 288 | } 289 | float fPercent = (float) (m_mbBufBegin * 1.0 / m_mbBufLen); 290 | String strPercent = df.format(fPercent * 100) + "%"; 291 | int nPercentWidth = (int) mPaint.measureText("999.9%") + 1; 292 | c.drawText(strPercent, mWidth - nPercentWidth, mHeight - 5, mPaint); 293 | } 294 | 295 | public void setBgBitmap(Bitmap BG) { 296 | m_book_bg = BG; 297 | } 298 | 299 | public boolean isFirstPage() { 300 | return m_isfirstPage; 301 | } 302 | 303 | public boolean isLastPage() { 304 | return m_islastPage; 305 | } 306 | 307 | public String getFileName() { 308 | return fileName; 309 | } 310 | 311 | public int getCurPostion() { 312 | return m_mbBufEnd; 313 | } 314 | 315 | public void setBeginPos(int pos) { 316 | m_mbBufEnd = pos; 317 | m_mbBufBegin = pos; 318 | } 319 | 320 | public int getBufLen() { 321 | return m_mbBufLen; 322 | } 323 | 324 | public String getOneLine() { 325 | return m_lines.toString().substring(0, 10); 326 | } 327 | 328 | public void changBackGround(int color) { 329 | mPaint.setColor(color); 330 | } 331 | 332 | public void setFontSize(int size) { 333 | m_fontSize = size; 334 | mPaint.setTextSize(size); 335 | } 336 | 337 | 338 | } 339 | -------------------------------------------------------------------------------- /src/com/ebook/bookpage/PageWidget.java: -------------------------------------------------------------------------------- 1 | package com.ebook.bookpage; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.ColorMatrix; 7 | import android.graphics.ColorMatrixColorFilter; 8 | import android.graphics.Matrix; 9 | import android.graphics.Paint; 10 | import android.graphics.Path; 11 | import android.graphics.PointF; 12 | import android.graphics.Region; 13 | import android.graphics.drawable.GradientDrawable; 14 | import android.view.MotionEvent; 15 | import android.view.View; 16 | import android.widget.Scroller; 17 | 18 | public class PageWidget extends View { 19 | 20 | private int mWidth = 480; 21 | private int mHeight = 800; 22 | private int mCornerX = 0; // 拖拽点对应的页脚 23 | private int mCornerY = 0; 24 | private Path mPath0; 25 | private Path mPath1; 26 | Bitmap mCurPageBitmap = null; // 当前页 27 | Bitmap mNextPageBitmap = null; 28 | 29 | PointF mTouch = new PointF(); // 拖拽点 30 | PointF mBezierStart1 = new PointF(); // 贝塞尔曲线起始点 31 | PointF mBezierControl1 = new PointF(); // 贝塞尔曲线控制点 32 | PointF mBeziervertex1 = new PointF(); // 贝塞尔曲线顶点 33 | PointF mBezierEnd1 = new PointF(); // 贝塞尔曲线结束点 34 | 35 | PointF mBezierStart2 = new PointF(); // 另一条贝塞尔曲线 36 | PointF mBezierControl2 = new PointF(); 37 | PointF mBeziervertex2 = new PointF(); 38 | PointF mBezierEnd2 = new PointF(); 39 | 40 | float mMiddleX; 41 | float mMiddleY; 42 | float mDegrees; 43 | float mTouchToCornerDis; 44 | ColorMatrixColorFilter mColorMatrixFilter; 45 | Matrix mMatrix; 46 | float[] mMatrixArray = { 0, 0, 0, 0, 0, 0, 0, 0, 1.0f }; 47 | 48 | boolean mIsRTandLB; // 是否属于右上左下 49 | float mMaxLength = (float) Math.hypot(mWidth, mHeight); 50 | int[] mBackShadowColors; 51 | int[] mFrontShadowColors; 52 | GradientDrawable mBackShadowDrawableLR; 53 | GradientDrawable mBackShadowDrawableRL; 54 | GradientDrawable mFolderShadowDrawableLR; 55 | GradientDrawable mFolderShadowDrawableRL; 56 | 57 | GradientDrawable mFrontShadowDrawableHBT; 58 | GradientDrawable mFrontShadowDrawableHTB; 59 | GradientDrawable mFrontShadowDrawableVLR; 60 | GradientDrawable mFrontShadowDrawableVRL; 61 | 62 | Paint mPaint; 63 | 64 | Scroller mScroller; 65 | 66 | public PageWidget(Context context) { 67 | super(context); 68 | // TODO Auto-generated constructor stub 69 | mPath0 = new Path(); 70 | mPath1 = new Path(); 71 | createDrawable(); 72 | 73 | mPaint = new Paint(); 74 | mPaint.setStyle(Paint.Style.FILL); 75 | 76 | ColorMatrix cm = new ColorMatrix(); 77 | float array[] = { 0.55f, 0, 0, 0, 80.0f, 0, 0.55f, 0, 0, 80.0f, 0, 0, 78 | 0.55f, 0, 80.0f, 0, 0, 0, 0.2f, 0 }; 79 | cm.set(array); 80 | mColorMatrixFilter = new ColorMatrixColorFilter(cm); 81 | mMatrix = new Matrix(); 82 | mScroller = new Scroller(getContext()); 83 | 84 | mTouch.x = 0.01f; // 不让x,y为0,否则在点计算时会有问题 85 | mTouch.y = 0.01f; 86 | 87 | } 88 | 89 | public void setWidth(int width) { 90 | mWidth = width; 91 | } 92 | 93 | public void setHeight(int height) { 94 | mHeight = height; 95 | } 96 | 97 | /** 98 | * Author : hmg25 Version: 1.0 Description : 计算拖拽点对应的拖拽脚 99 | */ 100 | public void calcCornerXY(float x, float y) { 101 | if (x <= mWidth / 2) 102 | mCornerX = 0; 103 | else 104 | mCornerX = mWidth; 105 | if (y <= mHeight / 2) 106 | mCornerY = 0; 107 | else 108 | mCornerY = mHeight; 109 | if ((mCornerX == 0 && mCornerY == mHeight) 110 | || (mCornerX == mWidth && mCornerY == 0)) 111 | mIsRTandLB = true; 112 | else 113 | mIsRTandLB = false; 114 | } 115 | 116 | public boolean doTouchEvent(MotionEvent event) { 117 | // TODO Auto-generated method stub 118 | if (event.getAction() == MotionEvent.ACTION_MOVE) { 119 | mTouch.x = event.getX(); 120 | mTouch.y = event.getY(); 121 | this.postInvalidate(); 122 | } 123 | if (event.getAction() == MotionEvent.ACTION_DOWN) { 124 | mTouch.x = event.getX(); 125 | mTouch.y = event.getY(); 126 | // calcCornerXY(mTouch.x, mTouch.y); 127 | // this.postInvalidate(); 128 | } 129 | if (event.getAction() == MotionEvent.ACTION_UP) { 130 | if (canDragOver()) { 131 | startAnimation(1200); 132 | } else { 133 | mTouch.x = mCornerX - 0.09f; 134 | mTouch.y = mCornerY - 0.09f; 135 | } 136 | 137 | this.postInvalidate(); 138 | } 139 | // return super.onTouchEvent(event); 140 | this.postInvalidate(); 141 | return true; 142 | } 143 | /** 144 | * Author : hmg25 Version: 1.0 Description : 求解直线P1P2和直线P3P4的交点坐标 145 | */ 146 | public PointF getCross(PointF P1, PointF P2, PointF P3, PointF P4) { 147 | PointF CrossP = new PointF(); 148 | // 二元函数通式: y=ax+b 149 | float a1 = (P2.y - P1.y) / (P2.x - P1.x); 150 | float b1 = ((P1.x * P2.y) - (P2.x * P1.y)) / (P1.x - P2.x); 151 | 152 | float a2 = (P4.y - P3.y) / (P4.x - P3.x); 153 | float b2 = ((P3.x * P4.y) - (P4.x * P3.y)) / (P3.x - P4.x); 154 | CrossP.x = (b2 - b1) / (a1 - a2); 155 | CrossP.y = a1 * CrossP.x + b1; 156 | return CrossP; 157 | } 158 | 159 | private void calcPoints() { 160 | mMiddleX = (mTouch.x + mCornerX) / 2; 161 | mMiddleY = (mTouch.y + mCornerY) / 2; 162 | mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY) 163 | * (mCornerY - mMiddleY) / (mCornerX - mMiddleX); 164 | mBezierControl1.y = mCornerY; 165 | mBezierControl2.x = mCornerX; 166 | mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX) 167 | * (mCornerX - mMiddleX) / (mCornerY - mMiddleY); 168 | 169 | mBezierStart1.x = mBezierControl1.x - (mCornerX - mBezierControl1.x) 170 | / 2; 171 | mBezierStart1.y = mCornerY; 172 | 173 | // 当mBezierStart1.x < 0或者mBezierStart1.x > 480时 174 | // 如果继续翻页,会出现BUG故在此限制 175 | if (mTouch.x > 0 && mTouch.x < mWidth) { 176 | if (mBezierStart1.x < 0 || mBezierStart1.x > mWidth) { 177 | if (mBezierStart1.x < 0) 178 | mBezierStart1.x = mWidth - mBezierStart1.x; 179 | 180 | float f1 = Math.abs(mCornerX - mTouch.x); 181 | float f2 = mWidth * f1 / mBezierStart1.x; 182 | mTouch.x = Math.abs(mCornerX - f2); 183 | 184 | float f3 = Math.abs(mCornerX - mTouch.x) 185 | * Math.abs(mCornerY - mTouch.y) / f1; 186 | mTouch.y = Math.abs(mCornerY - f3); 187 | 188 | mMiddleX = (mTouch.x + mCornerX) / 2; 189 | mMiddleY = (mTouch.y + mCornerY) / 2; 190 | 191 | mBezierControl1.x = mMiddleX - (mCornerY - mMiddleY) 192 | * (mCornerY - mMiddleY) / (mCornerX - mMiddleX); 193 | mBezierControl1.y = mCornerY; 194 | 195 | mBezierControl2.x = mCornerX; 196 | mBezierControl2.y = mMiddleY - (mCornerX - mMiddleX) 197 | * (mCornerX - mMiddleX) / (mCornerY - mMiddleY); 198 | // Log.i("hmg", "mTouchX --> " + mTouch.x + " mTouchY--> " 199 | // + mTouch.y); 200 | // Log.i("hmg", "mBezierControl1.x-- " + mBezierControl1.x 201 | // + " mBezierControl1.y -- " + mBezierControl1.y); 202 | // Log.i("hmg", "mBezierControl2.x -- " + mBezierControl2.x 203 | // + " mBezierControl2.y -- " + mBezierControl2.y); 204 | mBezierStart1.x = mBezierControl1.x 205 | - (mCornerX - mBezierControl1.x) / 2; 206 | } 207 | } 208 | mBezierStart2.x = mCornerX; 209 | mBezierStart2.y = mBezierControl2.y - (mCornerY - mBezierControl2.y) 210 | / 2; 211 | 212 | mTouchToCornerDis = (float) Math.hypot((mTouch.x - mCornerX), 213 | (mTouch.y - mCornerY)); 214 | 215 | mBezierEnd1 = getCross(mTouch, mBezierControl1, mBezierStart1, 216 | mBezierStart2); 217 | mBezierEnd2 = getCross(mTouch, mBezierControl2, mBezierStart1, 218 | mBezierStart2); 219 | 220 | mBeziervertex1.x = (mBezierStart1.x + 2 * mBezierControl1.x + mBezierEnd1.x) / 4; 221 | mBeziervertex1.y = (2 * mBezierControl1.y + mBezierStart1.y + mBezierEnd1.y) / 4; 222 | mBeziervertex2.x = (mBezierStart2.x + 2 * mBezierControl2.x + mBezierEnd2.x) / 4; 223 | mBeziervertex2.y = (2 * mBezierControl2.y + mBezierStart2.y + mBezierEnd2.y) / 4; 224 | } 225 | 226 | /** 227 | * 绘制当前页 228 | */ 229 | private void drawCurrentPageArea(Canvas canvas, Bitmap bitmap, Path path) { 230 | mPath0.reset(); 231 | mPath0.moveTo(mBezierStart1.x, mBezierStart1.y); 232 | mPath0.quadTo(mBezierControl1.x, mBezierControl1.y, mBezierEnd1.x, 233 | mBezierEnd1.y); 234 | mPath0.lineTo(mTouch.x, mTouch.y); 235 | mPath0.lineTo(mBezierEnd2.x, mBezierEnd2.y); 236 | mPath0.quadTo(mBezierControl2.x, mBezierControl2.y, mBezierStart2.x, 237 | mBezierStart2.y); 238 | mPath0.lineTo(mCornerX, mCornerY); 239 | mPath0.close(); 240 | 241 | canvas.save(); 242 | canvas.clipPath(path, Region.Op.XOR); 243 | canvas.drawBitmap(bitmap, 0, 0, null); 244 | canvas.restore(); 245 | 246 | } 247 | 248 | /** 249 | * 绘制下一页 250 | */ 251 | private void drawNextPageAreaAndShadow(Canvas canvas, Bitmap bitmap) { 252 | mPath1.reset(); 253 | mPath1.moveTo(mBezierStart1.x, mBezierStart1.y); 254 | mPath1.lineTo(mBeziervertex1.x, mBeziervertex1.y); 255 | mPath1.lineTo(mBeziervertex2.x, mBeziervertex2.y); 256 | mPath1.lineTo(mBezierStart2.x, mBezierStart2.y); 257 | mPath1.lineTo(mCornerX, mCornerY); 258 | mPath1.close(); 259 | 260 | mDegrees = (float) Math.toDegrees(Math.atan2(mBezierControl1.x 261 | - mCornerX, mBezierControl2.y - mCornerY)); 262 | int leftx; 263 | int rightx; 264 | GradientDrawable mBackShadowDrawable; 265 | if (mIsRTandLB) { 266 | leftx = (int) (mBezierStart1.x); 267 | rightx = (int) (mBezierStart1.x + mTouchToCornerDis / 4); 268 | mBackShadowDrawable = mBackShadowDrawableLR; 269 | } else { 270 | leftx = (int) (mBezierStart1.x - mTouchToCornerDis / 4); 271 | rightx = (int) mBezierStart1.x; 272 | mBackShadowDrawable = mBackShadowDrawableRL; 273 | } 274 | canvas.save(); 275 | canvas.clipPath(mPath0); 276 | canvas.clipPath(mPath1, Region.Op.INTERSECT); 277 | canvas.drawBitmap(bitmap, 0, 0, null); 278 | canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y); 279 | mBackShadowDrawable.setBounds(leftx, (int) mBezierStart1.y, rightx, 280 | (int) (mMaxLength + mBezierStart1.y)); 281 | mBackShadowDrawable.draw(canvas); 282 | canvas.restore(); 283 | } 284 | 285 | public void setBitmaps(Bitmap bm1, Bitmap bm2) { 286 | mCurPageBitmap = bm1; 287 | mNextPageBitmap = bm2; 288 | } 289 | 290 | public void setScreen(int w, int h) { 291 | mWidth = w; 292 | mHeight = h; 293 | } 294 | 295 | public void onDraw(Canvas canvas) { 296 | canvas.drawColor(0xFFAAAAAA); 297 | calcPoints(); 298 | drawCurrentPageArea(canvas, mCurPageBitmap, mPath0); 299 | drawNextPageAreaAndShadow(canvas, mNextPageBitmap); 300 | drawCurrentPageShadow(canvas); 301 | drawCurrentBackArea(canvas, mCurPageBitmap); 302 | } 303 | 304 | /** 305 | * 创建阴影的GradientDrawable 306 | */ 307 | private void createDrawable() { 308 | int[] color = { 0x333333, 0xb0333333 }; 309 | mFolderShadowDrawableRL = new GradientDrawable( 310 | GradientDrawable.Orientation.RIGHT_LEFT, color); 311 | mFolderShadowDrawableRL 312 | .setGradientType(GradientDrawable.LINEAR_GRADIENT); 313 | 314 | mFolderShadowDrawableLR = new GradientDrawable( 315 | GradientDrawable.Orientation.LEFT_RIGHT, color); 316 | mFolderShadowDrawableLR 317 | .setGradientType(GradientDrawable.LINEAR_GRADIENT); 318 | 319 | mBackShadowColors = new int[] { 0xff111111, 0x111111 }; 320 | mBackShadowDrawableRL = new GradientDrawable( 321 | GradientDrawable.Orientation.RIGHT_LEFT, mBackShadowColors); 322 | mBackShadowDrawableRL.setGradientType(GradientDrawable.LINEAR_GRADIENT); 323 | 324 | mBackShadowDrawableLR = new GradientDrawable( 325 | GradientDrawable.Orientation.LEFT_RIGHT, mBackShadowColors); 326 | mBackShadowDrawableLR.setGradientType(GradientDrawable.LINEAR_GRADIENT); 327 | 328 | mFrontShadowColors = new int[] { 0x80111111, 0x111111 }; 329 | mFrontShadowDrawableVLR = new GradientDrawable( 330 | GradientDrawable.Orientation.LEFT_RIGHT, mFrontShadowColors); 331 | mFrontShadowDrawableVLR 332 | .setGradientType(GradientDrawable.LINEAR_GRADIENT); 333 | mFrontShadowDrawableVRL = new GradientDrawable( 334 | GradientDrawable.Orientation.RIGHT_LEFT, mFrontShadowColors); 335 | mFrontShadowDrawableVRL 336 | .setGradientType(GradientDrawable.LINEAR_GRADIENT); 337 | 338 | mFrontShadowDrawableHTB = new GradientDrawable( 339 | GradientDrawable.Orientation.TOP_BOTTOM, mFrontShadowColors); 340 | mFrontShadowDrawableHTB 341 | .setGradientType(GradientDrawable.LINEAR_GRADIENT); 342 | 343 | mFrontShadowDrawableHBT = new GradientDrawable( 344 | GradientDrawable.Orientation.BOTTOM_TOP, mFrontShadowColors); 345 | mFrontShadowDrawableHBT 346 | .setGradientType(GradientDrawable.LINEAR_GRADIENT); 347 | } 348 | 349 | /** 350 | * 绘制翻起页的阴影 351 | */ 352 | public void drawCurrentPageShadow(Canvas canvas) { 353 | double degree; 354 | if (mIsRTandLB) { 355 | degree = Math.PI 356 | / 4 357 | - Math.atan2(mBezierControl1.y - mTouch.y, mTouch.x 358 | - mBezierControl1.x); 359 | } else { 360 | degree = Math.PI 361 | / 4 362 | - Math.atan2(mTouch.y - mBezierControl1.y, mTouch.x 363 | - mBezierControl1.x); 364 | } 365 | // 翻起页阴影顶点与touch点的距离 366 | double d1 = (float) 25 * 1.414 * Math.cos(degree); 367 | double d2 = (float) 25 * 1.414 * Math.sin(degree); 368 | float x = (float) (mTouch.x + d1); 369 | float y; 370 | if (mIsRTandLB) { 371 | y = (float) (mTouch.y + d2); 372 | } else { 373 | y = (float) (mTouch.y - d2); 374 | } 375 | mPath1.reset(); 376 | mPath1.moveTo(x, y); 377 | mPath1.lineTo(mTouch.x, mTouch.y); 378 | mPath1.lineTo(mBezierControl1.x, mBezierControl1.y); 379 | mPath1.lineTo(mBezierStart1.x, mBezierStart1.y); 380 | mPath1.close(); 381 | float rotateDegrees; 382 | canvas.save(); 383 | 384 | canvas.clipPath(mPath0, Region.Op.XOR); 385 | canvas.clipPath(mPath1, Region.Op.INTERSECT); 386 | int leftx; 387 | int rightx; 388 | GradientDrawable mCurrentPageShadow; 389 | if (mIsRTandLB) { 390 | leftx = (int) (mBezierControl1.x); 391 | rightx = (int) mBezierControl1.x + 25; 392 | mCurrentPageShadow = mFrontShadowDrawableVLR; 393 | } else { 394 | leftx = (int) (mBezierControl1.x - 25); 395 | rightx = (int) mBezierControl1.x + 1; 396 | mCurrentPageShadow = mFrontShadowDrawableVRL; 397 | } 398 | 399 | rotateDegrees = (float) Math.toDegrees(Math.atan2(mTouch.x 400 | - mBezierControl1.x, mBezierControl1.y - mTouch.y)); 401 | canvas.rotate(rotateDegrees, mBezierControl1.x, mBezierControl1.y); 402 | mCurrentPageShadow.setBounds(leftx, 403 | (int) (mBezierControl1.y - mMaxLength), rightx, 404 | (int) (mBezierControl1.y)); 405 | mCurrentPageShadow.draw(canvas); 406 | canvas.restore(); 407 | 408 | mPath1.reset(); 409 | mPath1.moveTo(x, y); 410 | mPath1.lineTo(mTouch.x, mTouch.y); 411 | mPath1.lineTo(mBezierControl2.x, mBezierControl2.y); 412 | mPath1.lineTo(mBezierStart2.x, mBezierStart2.y); 413 | mPath1.close(); 414 | canvas.save(); 415 | canvas.clipPath(mPath0, Region.Op.XOR); 416 | canvas.clipPath(mPath1, Region.Op.INTERSECT); 417 | if (mIsRTandLB) { 418 | leftx = (int) (mBezierControl2.y); 419 | rightx = (int) (mBezierControl2.y + 25); 420 | mCurrentPageShadow = mFrontShadowDrawableHTB; 421 | } else { 422 | leftx = (int) (mBezierControl2.y - 25); 423 | rightx = (int) (mBezierControl2.y + 1); 424 | mCurrentPageShadow = mFrontShadowDrawableHBT; 425 | } 426 | rotateDegrees = (float) Math.toDegrees(Math.atan2(mBezierControl2.y 427 | - mTouch.y, mBezierControl2.x - mTouch.x)); 428 | canvas.rotate(rotateDegrees, mBezierControl2.x, mBezierControl2.y); 429 | float temp; 430 | if (mBezierControl2.y < 0) 431 | temp = mBezierControl2.y - mHeight; 432 | else 433 | temp = mBezierControl2.y; 434 | 435 | int hmg = (int) Math.hypot(mBezierControl2.x, temp); 436 | if (hmg > mMaxLength) 437 | mCurrentPageShadow 438 | .setBounds((int) (mBezierControl2.x - 25) - hmg, leftx, 439 | (int) (mBezierControl2.x + mMaxLength) - hmg, 440 | rightx); 441 | else 442 | mCurrentPageShadow.setBounds( 443 | (int) (mBezierControl2.x - mMaxLength), leftx, 444 | (int) (mBezierControl2.x), rightx); 445 | 446 | // Log.i("hmg", "mBezierControl2.x " + mBezierControl2.x 447 | // + " mBezierControl2.y " + mBezierControl2.y); 448 | mCurrentPageShadow.draw(canvas); 449 | canvas.restore(); 450 | } 451 | 452 | /** 453 | * 绘制翻起页背面 454 | */ 455 | private void drawCurrentBackArea(Canvas canvas, Bitmap bitmap) { 456 | int i = (int) (mBezierStart1.x + mBezierControl1.x) / 2; 457 | float f1 = Math.abs(i - mBezierControl1.x); 458 | int i1 = (int) (mBezierStart2.y + mBezierControl2.y) / 2; 459 | float f2 = Math.abs(i1 - mBezierControl2.y); 460 | float f3 = Math.min(f1, f2); 461 | mPath1.reset(); 462 | mPath1.moveTo(mBeziervertex2.x, mBeziervertex2.y); 463 | mPath1.lineTo(mBeziervertex1.x, mBeziervertex1.y); 464 | mPath1.lineTo(mBezierEnd1.x, mBezierEnd1.y); 465 | mPath1.lineTo(mTouch.x, mTouch.y); 466 | mPath1.lineTo(mBezierEnd2.x, mBezierEnd2.y); 467 | mPath1.close(); 468 | GradientDrawable mFolderShadowDrawable; 469 | int left; 470 | int right; 471 | if (mIsRTandLB) { 472 | left = (int) (mBezierStart1.x - 1); 473 | right = (int) (mBezierStart1.x + f3 + 1); 474 | mFolderShadowDrawable = mFolderShadowDrawableLR; 475 | } else { 476 | left = (int) (mBezierStart1.x - f3 - 1); 477 | right = (int) (mBezierStart1.x + 1); 478 | mFolderShadowDrawable = mFolderShadowDrawableRL; 479 | } 480 | canvas.save(); 481 | canvas.clipPath(mPath0); 482 | canvas.clipPath(mPath1, Region.Op.INTERSECT); 483 | 484 | mPaint.setColorFilter(mColorMatrixFilter); 485 | 486 | float dis = (float) Math.hypot(mCornerX - mBezierControl1.x, 487 | mBezierControl2.y - mCornerY); 488 | float f8 = (mCornerX - mBezierControl1.x) / dis; 489 | float f9 = (mBezierControl2.y - mCornerY) / dis; 490 | mMatrixArray[0] = 1 - 2 * f9 * f9; 491 | mMatrixArray[1] = 2 * f8 * f9; 492 | mMatrixArray[3] = mMatrixArray[1]; 493 | mMatrixArray[4] = 1 - 2 * f8 * f8; 494 | mMatrix.reset(); 495 | mMatrix.setValues(mMatrixArray); 496 | mMatrix.preTranslate(-mBezierControl1.x, -mBezierControl1.y); 497 | mMatrix.postTranslate(mBezierControl1.x, mBezierControl1.y); 498 | canvas.drawBitmap(bitmap, mMatrix, mPaint); 499 | // canvas.drawBitmap(bitmap, mMatrix, null); 500 | mPaint.setColorFilter(null); 501 | canvas.rotate(mDegrees, mBezierStart1.x, mBezierStart1.y); 502 | mFolderShadowDrawable.setBounds(left, (int) mBezierStart1.y, right, 503 | (int) (mBezierStart1.y + mMaxLength)); 504 | mFolderShadowDrawable.draw(canvas); 505 | canvas.restore(); 506 | } 507 | 508 | public void computeScroll() { 509 | super.computeScroll(); 510 | if (mScroller.computeScrollOffset()) { 511 | float x = mScroller.getCurrX(); 512 | float y = mScroller.getCurrY(); 513 | mTouch.x = x; 514 | mTouch.y = y; 515 | postInvalidate(); 516 | } 517 | } 518 | 519 | private void startAnimation(int delayMillis) { 520 | int dx, dy; 521 | // dx 水平方向滑动的距离,负值会使滚动向左滚动 522 | // dy 垂直方向滑动的距离,负值会使滚动向上滚动 523 | if (mCornerX > 0) { 524 | dx = -(int) (mWidth + mTouch.x); 525 | } else { 526 | dx = (int) (mWidth - mTouch.x + mWidth); 527 | } 528 | if (mCornerY > 0) { 529 | dy = (int) (mHeight - mTouch.y); 530 | } else { 531 | dy = (int) (1 - mTouch.y); // 防止mTouch.y最终变为0 532 | } 533 | mScroller.startScroll((int) mTouch.x, (int) mTouch.y, dx, dy, 534 | delayMillis); 535 | } 536 | 537 | public void abortAnimation() { 538 | if (!mScroller.isFinished()) { 539 | mScroller.abortAnimation(); 540 | } 541 | } 542 | 543 | public boolean canDragOver() { 544 | if (mTouchToCornerDis > mWidth / 10) 545 | return true; 546 | return false; 547 | } 548 | 549 | /** 550 | * 是否从左边翻向右边 551 | */ 552 | public boolean DragToRight() { 553 | if (mCornerX > 0) 554 | return false; 555 | return true; 556 | } 557 | } 558 | -------------------------------------------------------------------------------- /src/com/ebook/scansd/BookMark.java: -------------------------------------------------------------------------------- 1 | package com.ebook.scansd; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | 7 | import android.content.Context; 8 | 9 | public class BookMark { 10 | 11 | Context mContext; 12 | String fileName; 13 | 14 | public BookMark(Context context, String filename) { 15 | mContext = context; 16 | this.fileName = filename.substring(0, filename.lastIndexOf(".") + 1) + "mark.txt"; 17 | } 18 | 19 | public BookMark(String filename) { 20 | // TODO Auto-generated constructor stub 21 | this.fileName = filename.substring(0, filename.lastIndexOf(".") + 1) + "mark.txt"; 22 | } 23 | 24 | public void setContext(Context context) { 25 | mContext = context; 26 | } 27 | 28 | final static String DATA_URL = "/data/data"; 29 | 30 | public void saveFile(String string) { 31 | // File file = new File(DATA_URL + FILE_NAME); 32 | try { 33 | // FileOutputStream outputStream = new FileOutputStream(file); 34 | FileOutputStream outputStream = mContext.openFileOutput(fileName, 35 | Context.MODE_WORLD_READABLE); 36 | outputStream.write(string.getBytes()); 37 | outputStream.close(); 38 | } catch (Exception e) { 39 | // TODO: handle exception 40 | e.printStackTrace(); 41 | } 42 | } 43 | 44 | public String loadFile() { 45 | 46 | try { 47 | // File file = new File(DATA_URL + FILE_NAME); 48 | FileInputStream inputStream = mContext.openFileInput(fileName); 49 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 50 | byte[] buffer = new byte[1024]; 51 | int length = -1; 52 | while ((length = inputStream.read(buffer)) != -1) { 53 | stream.write(buffer, 0, length); 54 | } 55 | stream.close(); 56 | inputStream.close(); 57 | return stream.toString(); 58 | } catch (Exception e) { 59 | // TODO: handle exception 60 | e.printStackTrace(); 61 | } 62 | return null; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/com/ebook/scansd/ScanSD.java: -------------------------------------------------------------------------------- 1 | package com.ebook.scansd; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | public class ScanSD { 9 | String FILE_TYPE = ".txt"; 10 | private ArrayList list; 11 | 12 | public ScanSD(String fileType) { 13 | FILE_TYPE = fileType; 14 | list = new ArrayList(); 15 | } 16 | 17 | public ScanSD() { 18 | list = new ArrayList(); 19 | } 20 | 21 | public ArrayList> getMapData(ArrayList list) { 22 | ArrayList> mData = new ArrayList>(); 23 | HashMap item; 24 | 25 | int i = 0; 26 | String path; 27 | String name; 28 | for (i = 0; i < list.size(); i++) { 29 | item = new HashMap(); 30 | path = list.get(i).toString(); 31 | name = path.substring(path.lastIndexOf("/") + 1, path.length()); 32 | item.put("ItemName", name); 33 | item.put("ItemPath", path); 34 | mData.add(item); 35 | } 36 | return mData; 37 | } 38 | 39 | public ArrayList> getMapData(ArrayList list, int start, int end) { 40 | ArrayList> mData = new ArrayList>(); 41 | HashMap item; 42 | 43 | int i = 0; 44 | String path; 45 | String name; 46 | int tmp; 47 | if (end > list.size()) { 48 | tmp = list.size(); 49 | } else { 50 | tmp = end; 51 | } 52 | 53 | for (i = start; i < tmp; i++) { 54 | item = new HashMap(); 55 | path = list.get(i).toString(); 56 | name = path.substring(path.lastIndexOf("/") + 1, path.length()); 57 | item.put("ItemName", name); 58 | item.put("ItemPath", path); 59 | mData.add(item); 60 | } 61 | return mData; 62 | } 63 | 64 | protected void getAllFiles(File root, String fileType) { 65 | if (fileType == null) { 66 | fileType = FILE_TYPE; 67 | } 68 | File files[] = root.listFiles(); 69 | if (files != null) { 70 | for (File f: files) { 71 | 72 | if (f.isDirectory()) { 73 | getAllFiles(f, fileType); 74 | } else { 75 | if (f.getName().indexOf(fileType) > 0) { 76 | this.list.add(f); 77 | } 78 | } 79 | } 80 | } 81 | } 82 | 83 | public ArrayList getFileList() { 84 | getAllFiles(new File("/sdcard"), null); 85 | return list; 86 | } 87 | 88 | public ArrayList getFileList(String fileType) { 89 | getAllFiles(new File("/sdcard"), fileType); 90 | return list; 91 | } 92 | 93 | public void setGetFileType(String fileType) { 94 | FILE_TYPE = fileType; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/com/sqlite/DbHelper.java: -------------------------------------------------------------------------------- 1 | package com.sqlite; 2 | 3 | import android.content.ContentValues; 4 | import android.content.Context; 5 | import android.database.Cursor; 6 | import android.database.sqlite.SQLiteDatabase; 7 | import android.database.sqlite.SQLiteOpenHelper; 8 | 9 | public class DbHelper extends SQLiteOpenHelper { 10 | private final static String DATABASE_NAME = "sec_db"; 11 | private final static int DATABASE_VERSION = 1; 12 | private final static String TABLE_NAME = "book_mark"; 13 | public final static String FIELD_ID = "_id"; 14 | public final static String FIELD_FILENAME = "filename"; 15 | public final static String FIELD_BOOKMARK = "bookmark"; 16 | 17 | public DbHelper(Context context) { 18 | super(context, DATABASE_NAME, null, DATABASE_VERSION); 19 | } 20 | 21 | @Override 22 | public void onCreate(SQLiteDatabase db) { 23 | // TODO Auto-generated method stub 24 | StringBuffer sqlCreateCountTb = new StringBuffer(); 25 | sqlCreateCountTb.append("create table ").append(TABLE_NAME) 26 | .append("(_id integer primary key autoincrement,") 27 | .append(" filename text,") 28 | .append(" bookmark text);"); 29 | db.execSQL(sqlCreateCountTb.toString()); 30 | } 31 | 32 | @Override 33 | public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) { 34 | // TODO Auto-generated method stub 35 | String sql = " DROP TABLE IF EXISTS " + TABLE_NAME; 36 | db.execSQL(sql); 37 | onCreate(db); 38 | 39 | } 40 | 41 | public Cursor select() { 42 | SQLiteDatabase db = this.getReadableDatabase(); 43 | Cursor cursor = db.query(TABLE_NAME, null, null, null, null, null, 44 | " _id desc"); 45 | return cursor; 46 | } 47 | 48 | public long insert(String Title) { 49 | SQLiteDatabase db = this.getWritableDatabase(); 50 | ContentValues cv = new ContentValues(); 51 | cv.put(FIELD_BOOKMARK, Title); 52 | long row = db.insert(TABLE_NAME, null, cv); 53 | return row; 54 | } 55 | 56 | public long insert(String filename, String bookmark) { 57 | SQLiteDatabase db = this.getWritableDatabase(); 58 | ContentValues cv = new ContentValues(); 59 | cv.put(FIELD_FILENAME, filename); 60 | cv.put(FIELD_BOOKMARK, bookmark); 61 | long row = db.insert(TABLE_NAME, null, cv); 62 | return row; 63 | } 64 | 65 | public void delete(int id) { 66 | SQLiteDatabase db = this.getWritableDatabase(); 67 | String where = FIELD_ID + "=?"; 68 | String[] whereValue = { Integer.toString(id) }; 69 | db.delete(TABLE_NAME, where, whereValue); 70 | } 71 | 72 | public void update(int id, String filename, String bookmark) { 73 | SQLiteDatabase db = this.getWritableDatabase(); 74 | String where = FIELD_ID + "=?"; 75 | String[] whereValue = { Integer.toString(id) }; 76 | ContentValues cv = new ContentValues(); 77 | cv.put(FIELD_FILENAME, filename); 78 | cv.put(FIELD_BOOKMARK, bookmark); 79 | db.update(TABLE_NAME, cv, where, whereValue); 80 | } 81 | } 82 | --------------------------------------------------------------------------------