1,布局设置,LiearLayout 上中下三部分,其中小说主题内容部分为自定义view,比例是1:8:1
2,创建数据库表 两张表txt表和page表,两张表进行主外键关联
public class DBHelper extends SQLiteOpenHelper { public DBHelper(Context context) { super(context, "read.db", null, 1); } public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("create table txt(id Integer primry key,full_path text,now_page integer,over_flag integer)"); db.execSQL("create table page(id integer primary key,txt_id integer,page_num integer,content text)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } } 文本表<span style="font-size:12px;">public class TxtDB { public static void insertData(String fullPath) { String sql = "select id from txt where full_path=?"; Cursor c = Globals.helper.getReadableDatabase().rawQuery(sql, new String[]{fullPath}); if (!c.moveToFirst()) {//如果不存在数据则插入数据 sql = "insert into txt(id,full_path,now_page,over_flag) values(?,?,?,?)"; Globals.helper.getWritableDatabase().execSQL(sql, new Object[]{1,fullPath,1,0}); } c.close(); } public static Map<String, Object> loadData(String fullPath) { Map<String, Object> map = new HashMap<>(); String sql = "select id,now_page,over_flag from txt where full_path=?"; Cursor c = Globals.helper.getReadableDatabase().rawQuery(sql, new String[]{fullPath}); while (c.moveToNext()) { map.put("txtId", c.getInt(0)); map.put("nowPage", c.getInt(1)); map.put("overFlag", c.getInt(2)); } c.close(); return map; } public static void updateOverFlag(String fullPath) { String sql = "update txt set over_flag=1 where full_path=?"; Globals.helper.getWritableDatabase().execSQL(sql, new Object[]{fullPath}); } } </span>分页表
<span style="font-size:12px;">public class PageDB { private static int pageNum; public static void insertDate(Map<String, Object> map) { String sql = "insert into page(txt_id,page_num,content) values(?,?,?)"; Globals.helper.getWritableDatabase().execSQL(sql, new Object[]{map.get("txtId"), map.get("pageNum"), map.get("content")}); } public static String findContent(int txtId, int pageNum) { String content = null; String sql = "select content from page where txt_id=? and page_num=?"; Cursor c = Globals.helper.getReadableDatabase().rawQuery(sql, new String[]{txtId + "", pageNum + ""}); while (c.moveToNext()) { content = c.getString(0); } c.close(); return content; } public static int findPageNum(int txtId){ String sql="select count(*) from page where txt_id=?"; Cursor c= Globals.helper.getReadableDatabase().rawQuery(sql,new String[]{txtId+""}); while(c.moveToNext()){ pageNum=c.getInt(0); } c.close(); return pageNum; } }</span>
3,定义一个全局可以使用的类Globals ,在里面设置页面内容,每行显示的字数,字间距,行间距,页边距,获得安卓设备的屏幕宽度和高度
public class Globals { public static int SCREEN_WIDTH; public static int SCREEN_HEIGHT; public static int LINE_CHAR_COUNT=20;//每行显示20个字 public static int CHAR_SEP=2;//字间距 public static int PAGE_SEP=5;//页边距 public static int LINE_SEP=2;//行间距 public static int CHAR_SIZE;//字符大小,需计算,保证能根据屏幕大小自适应 public static int LINE_COUNT;//每页显示的行数,需计算。 public static void init(Activity a){ SCREEN_WIDTH=a.getWindowManager().getDefaultDisplay().getWidth();//获得屏幕宽度 SCREEN_HEIGHT=a.getWindowManager().getDefaultDisplay().getHeight();//获得屏幕高度 CHAR_SIZE=(SCREEN_WIDTH-PAGE_SEP*2-(LINE_CHAR_COUNT-1)*CHAR_SEP)/LINE_CHAR_COUNT;//计算出字符大小 LINE_COUNT=SCREEN_HEIGHT*4/5/(CHAR_SIZE+LINE_SEP);//计算每页显示的行数,并跟布局相适应,占屏幕的五分之四 } } 4,自定义MyView,滑动翻页 <pre name="code" class="java">public class MyView extends View { private String content; private MainActivity a; private float startX; private float nowX; private String preContent;//准备上一页和下一页的内容 private String nextContent; public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); a = (MainActivity) context; this.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { } }); this.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { startX = event.getX(); } else if (event.getAction() == MotionEvent.ACTION_MOVE) { nowX = event.getX(); postInvalidate();//重新调用onDraw方法 } else if (event.getAction() == MotionEvent.ACTION_UP) { if (Math.abs(nowX - startX) >= 50) {//nowX和startX的绝对值大于50 的话才执行翻页 if (nowX > startX) {//上一页 if (a.getNowPageNum() > 1) { a.setNowPageNum(a.getNowPageNum() - 1);//翻到上一页 changeData(); } } if (nowX < startX) {//下一页 if (a.getNowPageNum() < a.getPageNum()) { a.setNowPageNum(a.getNowPageNum() + 1);//翻到下一页 changeData(); } } } startX = 0; nowX = 0; } return false; } }); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public void changeData() { content = PageDB.findContent((int) a.getTxtMap().get("txtId"),a.getNowPageNum()); if (a.getNowPageNum() > 1) {//当前页不是第一页的时候 preContent = PageDB.findContent((int) a.getTxtMap().get("txtId"), a.getNowPageNum() - 1); } else { preContent = null; } if (a.getNowPageNum() < a.getPageNum()) {//当前页不是最后一页 nextContent = PageDB.findContent((int) a.getTxtMap().get("txtId"),a.getNowPageNum()+ 1); } else { nextContent = null; } a.getHandler().sendEmptyMessage(1); super.postInvalidate();//调用OnDraw方法; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (content != null) { String[] allValues = content.split(Globals.END_FLAG); for (int i = 0; i < allValues.length; i++) { for (int j = 0; j < allValues[i].length(); j++) { if (j + i * Globals.char_line_conut < content.length()) { Paint paint = new Paint(); paint.setColor(Color.BLACK); paint.setTextSize(Globals.char_size); canvas.drawText(String.valueOf(allValues[i].charAt(j)), Globals.page_sep + j * (Globals.char_size + Globals.char_sep) + (nowX-startX), i * (Globals.char_size + Globals.line_sep), paint); } } } } if (nowX > startX && preContent != null) { String[] allValues = preContent.split(Globals.END_FLAG); for (int i = 0; i < allValues.length; i++) { for (int j = 0; j < allValues[i].length(); j++) { if (j + i * Globals.char_line_conut < content.length()) { Paint paint = new Paint(); paint.setColor(Color.BLACK); paint.setTextSize(Globals.char_size); canvas.drawText(String.valueOf(allValues[i].charAt(j)), Globals.page_sep + j * (Globals.char_size + Globals.char_sep) +(nowX-startX) -Globals.screen_width, i * (Globals.char_size + Globals.line_sep), paint); } } } } if (nowX < startX && nextContent != null) { String[] allValues = nextContent.split(Globals.END_FLAG); for (int i = 0; i < allValues.length; i++) { for (int j = 0; j < allValues[i].length(); j++) { if (j + i * Globals.char_line_conut < content.length()) { Paint paint = new Paint(); paint.setColor(Color.BLACK); paint.setTextSize(Globals.char_size); canvas.drawText(String.valueOf(allValues[i].charAt(j)), Globals.page_sep + j * (Globals.char_size + Globals.char_sep) +(nowX-startX) +Globals.screen_width, i * (Globals.char_size + Globals.line_sep), paint); } } } } } }
5,将文本存放在sdcard的根目录,以西游记作为示范,获得文本的绝对路径,用字符流进行按行读取
<pre name="code" class="java">public class MainActivity extends AppCompatActivity { static MyView contentView; static TextView pageView; private Map<String, Object> txtMap; private Map<String, Object> pageMap = new HashMap<>(); private StringBuffer sb = new StringBuffer(); private int lineCount = 0;//每页的行数 static int pageNum = 1;//总页数 static int nowPageNum = 1;//当前页数 private String fullPath; static Handler handler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 0) { pageView.setText("正在分页,已经分解:" + pageNum); } else if (msg.what == 1) { pageView.setText("分页已经完成" + nowPageNum + "/" + pageNum); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Globals.init(this); setContentView(R.layout.activity_main); contentView = (MyView) findViewById(R.id.content_view); pageView = (TextView) findViewById(R.id.page_view); fullPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/xiyouji.txt";//获取文件路径 TxtDB.insertIntoTxt(fullPath); txtMap = TxtDB.loadTxtByFullpath(fullPath); if ((int) txtMap.get("overFlag") == 0) { //还未进行分页 new Thread() { @Override public void run() { try { BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fullPath), "GBK")); String line = null; while ((line = br.readLine()) != null) { while (line.length() > Globals.char_line_conut) { String str = line.substring(0, Globals.char_line_conut); line = line.substring(Globals.char_line_conut); addLine(str); } addLine(line);//行余下的不足以凑成一行的字数添加成一行 } br.close(); handler.sendEmptyMessage(1); TxtDB.updateOverFlag(fullPath); } catch (Exception e) { e.printStackTrace(); } } }.start(); } else { //已经分页完成 pageNum = PageDB.getPageCount((int) txtMap.get("txtId")); nowPageNum = (int) txtMap.get("nowPage"); contentView.changeData(); } } @Override protected void onDestroy() { TxtDB.updateNowPaga((int) txtMap.get("nowPage"), fullPath); super.onDestroy(); } public void addLine(String str) {//行凑成页之后存放到数据库中 sb.append(str); sb.append(Globals.END_FLAG); lineCount++; if (lineCount == Globals.line_count) { pageMap.put("txtid", txtMap.get("txtId")); pageMap.put("pagenum", pageNum++); pageMap.put("content", sb.toString()); PageDB.insertIntoPageDB(pageMap); if (pageNum == 10) { contentView.changeData(); } handler.sendEmptyMessage(0); sb = new StringBuffer(); lineCount = 0;//再次初始化供下次循环使用 } } public Map<String, Object> getTxtMap() { return txtMap; } public void setTxtMap(Map<String, Object> txtMap) { this.txtMap = txtMap; } public int getPageNum() { return pageNum; } public void setPageNum(int pageNum) { this.pageNum = pageNum; } public int getNowPageNum() { return nowPageNum; } public void setNowPageNum(int nowPageNum) { this.nowPageNum = nowPageNum; } public Handler getHandler() { return handler; } public void setHandler(Handler handler) { this.handler = handler; } public Map<String, Object> getPageMap() { return pageMap; } }
时间: 2024-10-01 05:13:25