最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android 如何從零開始寫一款書籍閱讀器的示例

 更新時(shí)間:2018年01月09日 14:09:23   作者:cpacm  
這篇文章主要介紹了Android 如何從零開始寫一款書籍閱讀器的示例,詳細(xì)的介紹了搭建整個(gè)閱讀器的框架,有興趣的可以了解一下

一款書籍閱讀器,需要以下功能才能說的上比較完整:

  1. 文字頁面展示,即書頁;
  2. 頁面之間的跳轉(zhuǎn)動畫,即翻頁動作;
  3. 能夠在每一頁上記錄閱讀進(jìn)度,即書簽;
  4. 能夠自由選擇文字并標(biāo)注,即筆記;
  5. 能夠設(shè)置一些屬性,如屏幕亮度,字體大小,主體顏色等,即個(gè)性化設(shè)置。

書籍閱讀器

這篇文章帶來的就是如何打造這么一款閱讀器。(由于整體代碼量比較大,所以我只能說說我的實(shí)現(xiàn)思路再加上部分的核心代碼來說明,不會有太多的代碼展示。)

翻頁動作——搭建整個(gè)閱讀器的框架

在閱讀器上的翻頁動作無外乎仿真和平移這兩種動畫,翻頁時(shí)需要準(zhǔn)備兩張頁面,一張是當(dāng)前頁,另一張是需要翻轉(zhuǎn)的下一頁。翻頁的過程就是對這兩個(gè)頁面的剪輯。

這里就不贅述翻頁的原理了(仿真翻頁可以由貝塞爾曲線計(jì)算坐標(biāo)繪制實(shí)現(xiàn),平移翻頁則是簡單坐標(biāo)平移變化),這里提供一些參考鏈接。

Github上的PageFlip庫

現(xiàn)在要做的就是將翻頁動作與 View 結(jié)合起來,我們新建一個(gè) PageAnimController 內(nèi)部實(shí)現(xiàn)翻頁動畫和動畫切換,同時(shí)設(shè)置 PageCarver 來監(jiān)聽翻頁動作,目的是為了能夠讓 view 檢測到翻頁動作。

 public interface PageCarver {
 
  void drawPage(Canvas canvas, int index);//繪制頁內(nèi)容
  Integer requestPrePage();//請求翻到上一頁
  Integer requestNextPage();//請求翻到下一頁
  void requestInvalidate();//刷新界面
  Integer getCurrentPageIndex();//獲取當(dāng)前頁

  /**
   * 開始動畫的回調(diào)
   *
   * @param isCancel 是否是取消動畫
   */
  void onStartAnim(boolean isCancel);

  /**
   * 結(jié)束動畫的回調(diào)
   *
   * @param isCancel 是否是取消動畫
   */
  void onStopAnim(boolean isCancel);
 }

新建 BaseReaderView 作為閱讀器的基礎(chǔ)視圖,兩者結(jié)合以便控制閱讀器的翻頁效果。

public abstract class BaseReaderView extends View implements PageAnimController.PageCarver{

 /**
  * 將View的繪制事件傳送給 PageAnimController 實(shí)現(xiàn)動畫繪制過程中
  * @param canvas
  * @return
  */
 @Override
 protected void onDraw(Canvas canvas) {
  if (pageAnimController == null || !pageAnimController.dispatchDrawPage(canvas, this)) {
   drawPage(canvas, currentPageIndex);
  }
 }
 
 /**
  * 將View的觸摸事件傳送給 PageAnimController 以便實(shí)現(xiàn)翻頁動畫 
  * @param event
  * @return
  */
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  pageAnimController.dispatchTouchEvent(event, this);
  return true;
 }
}

但是在翻頁動畫中是需要無數(shù)次的調(diào)用 drawPage 來繪制界面的,為了減少界面計(jì)算的開支必須要有一個(gè) Bitmap 緩存來降低消耗。復(fù)用時(shí)可以直接使用已經(jīng)生成的bitmap.

/**
 * <p>
 * 頁面快照,用來存儲閱讀器每一頁的內(nèi)容
 *
 * @author cpacm 2017/10/9
 */

public class PageSnapshot {
 private int pageIndex;
 private Bitmap mBitmap;
 private Canvas mCanvas;

 public Canvas beginRecording(int width, int height) {
  if (mBitmap == null) {
   mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
   mCanvas = new Canvas(mBitmap);
  } else {
   mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
  }
  return mCanvas;
 }

 public void draw(Canvas canvas) {
  if (null != mBitmap) {
   canvas.drawBitmap(mBitmap, 0, 0, null);
  }
 }

 public void destroy() {
  if (mBitmap != null && !mBitmap.isRecycled()) {
   mBitmap.recycle();
   mBitmap = null;
  }
 }
}

基礎(chǔ)模型如下圖所示:

頁面切換模型

現(xiàn)在我們來總結(jié)一下,這一部分我們搭建了閱讀器最基礎(chǔ)的框架,包括

(1) 翻頁動畫與閱讀器視圖的結(jié)合,能夠確保在View中正確監(jiān)聽翻頁動作,保證整個(gè)翻頁動作的準(zhǔn)確性。

(2) 利用 Bitmap 緩存優(yōu)化繪圖流程,保證翻頁動畫的流暢性。而后包括文字,圖片等元素的顯示都是繪制在這個(gè) Bitmap 上的。

書頁——組合模式,保證閱讀器高度可定制化

閱讀器模塊圖

一般來說,閱讀器獲取數(shù)據(jù)都是一章一章來的,不管是從網(wǎng)絡(luò)上還是本地。而獲取過來的數(shù)據(jù)閱讀器要進(jìn)行分頁才能展示。如上圖所示,書頁展示由 PageElement 模塊負(fù)責(zé),該模塊接收從 BookReaderView 傳入的章節(jié)數(shù)據(jù),然后再經(jīng)底下的4個(gè)模塊計(jì)算來分頁。

分頁模塊

  1. PageElement,分頁模塊:功能包括將傳入的章節(jié)數(shù)據(jù)分成數(shù)個(gè) PageData (生成的 PageData 個(gè)數(shù)即為該章節(jié)頁數(shù),PageData 記錄了每一頁開頭文字在章節(jié)的位置,同時(shí)包含該頁面HeaderData, LineData,HeadrData 和 FooterData 數(shù)據(jù)等。各個(gè) Data 里面記錄了相應(yīng)的文字信息,可以快速的定位到章節(jié)內(nèi)容中。);繪制頁面;緩存章節(jié)數(shù)據(jù)以便無縫切換章節(jié)。
  2. HeaderElement,頁頭部分:顯示章節(jié)的標(biāo)題;繪制每一頁的頭部。
  3. LineElement,文字行部分:測量一行文字需要的字?jǐn)?shù);測量行高;繪制行文字;繪制筆記內(nèi)容;測量每一個(gè)字在屏幕中的位置,用于筆記功能;
  4. ImageElement,圖片部分:測量圖片的寬高;繪制圖片。
  5. FooterElement,頁尾部分:繪制每一頁的頁尾,包括進(jìn)度,時(shí)間和電量。
 //摘自 PageElement 的 onDraw 方法
 @Override
 public void draw(Canvas canvas) {
  int index = drawPageIndex - startPageIndex;
  if (index < 0 || index >= pages.size()) return;
  BookPageData bookPageData = pages.get(index);
  int offsetX = bookSettingParams.paddingLeft;
  int offsetY = bookSettingParams.paddingTop;
  if (bookPageData == null) return;
  canvas.drawColor(bookSettingParams.getBgColor());
  bookHeaderElement.setChapterTitle(bookPageData.getChapterName());
  bookHeaderElement.setX(offsetX);
  bookHeaderElement.setY(offsetY);
  if (bookPageData.isChapterFirstPage()) {
   bookHeaderElement.drawFirstPage(canvas);
  } else {
   bookHeaderElement.draw(canvas);
  }

  bookFooterElement.setProgress(bookPageData.getPageIndex(), bookPageData.getPageNums());
  bookFooterElement.setX(offsetX);
  bookFooterElement.setY(offsetY + getHeight() - bookFooterElement.getHeight());
  bookFooterElement.draw(canvas);

  for (int i = 0; i < bookPageData.getDataList().size(); i++) {
   BookData bookData = bookPageData.getDataList().get(i);
   if (bookData instanceof BookLineData) {
    BookLineData bookLineData = (BookLineData) bookData;
    bookLineElement.setLineText(bookLineData.getContent());
    bookLineElement.setX(bookLineData.getPosition().x);
    bookLineElement.setY(bookLineData.getPosition().y);
    bookLineElement.drawWithDigests(canvas, bookLineData, bookReaderView.getCurrentDigests(index));
    //bookLineElement.draw(canvas);
   } else if (bookData instanceof BookImageData) {
    BookImageData bookImageData = (BookImageData) bookData;
    bookImageElement.setX(bookImageData.getPosition().x);
    bookImageElement.setY(bookImageData.getPosition().y);
    bookImageElement.syncDrawWithinBitmap(canvas, bookImageData, bookReaderView.getCacheBitmap(drawPageIndex));
   }
  }
 }

將書頁分成幾部分組合起來可以有效的減少代碼的耦合,而且可以自由的控制每一部分的修改,添加和移除。比如當(dāng)以后我想要加個(gè)批注的功能,可以再添加一個(gè)新的 Element ,再復(fù)寫其測量方法和繪制方法,就可以很方便的使用了。

總結(jié)一下:

(1) PageElement 利用各個(gè) Element 模塊將章節(jié)數(shù)據(jù)進(jìn)行測量分頁,每一頁 PageData 記錄著 LineData,ImageData,HeaderData和FooterData信息。繪圖時(shí)需要將各個(gè)信息填入 Element 中

(2) 繪圖時(shí)調(diào)用 PageElement 的 draw 方法,其 draw 方法再調(diào)用 各個(gè) Element 的 draw 方法以完成整個(gè)繪圖流程。

另外還需要提到的一點(diǎn)是閱讀器內(nèi)部維護(hù)了一個(gè)書頁的隊(duì)列,該隊(duì)列緩存了由三個(gè)章節(jié)數(shù)據(jù)轉(zhuǎn)化而來的書頁列表。比如說你正在閱讀第六章,那么隊(duì)列里面緩存的就是第五章,第六章和第七章的數(shù)據(jù),這樣就能實(shí)現(xiàn)上下章翻頁的無縫切換而不需要在翻至下一章時(shí)因?yàn)榈却碌恼鹿?jié)數(shù)據(jù)加載而中斷整個(gè)閱讀體驗(yàn)。

/**
 * <p>
 * 章節(jié)緩存構(gòu)成方案如下:
 * | -6,-5,-4,-3,-2,-1,0 | 1,2,3,4,5,6,7,8,9 | 10,11,12,13,14,15 | = pages
 * | cacheChapter1 | cacheChapter2 | cacheChapter3 |
 * startPageIndex = pageIndex:-6 endPageIndex = pageIndex:16
 * currentChapterStartIndex => pageIndex:1 => pages[7]
 * currentChapterEndIndex => pageIndex:10 => pages[16]
 * </p>
 */

書簽,筆記——記錄閱讀進(jìn)度

書簽

書簽的本質(zhì)就是記錄當(dāng)前頁的第一個(gè)文字在整章文本的位置,然后再加上書籍的id,章節(jié)的id(或序號)就能準(zhǔn)確定位。

筆記

要記錄筆記就需要文字選擇器來選擇文字,這個(gè)時(shí)候就需要知道每一個(gè)字在當(dāng)前的坐標(biāo)位置(之前用 LineElement 測量文字時(shí)已經(jīng)生成每個(gè)文字的位置)。

為了達(dá)到上圖的效果,就必須要處理在當(dāng)前頁的觸摸事件:

文字選擇流程

有些細(xì)節(jié)的處理沒有放到流程中,但大致意思是能明白的

// TextSelectorElement 上的觸摸分發(fā)方法
public boolean dispatchTouchEvent(final MotionEvent ev) {
 int key = ev.getAction();
 currentTouchPoint.set(ev.getX(), ev.getY());
 switch (key) {
  case MotionEvent.ACTION_DOWN:
   isPressInvalid = false;
   hasConsume = true;
   isDown = true;
   mTouchDownPoint.set(ev.getX(), ev.getY());
   // 該方法中會記錄isBookDigestDown的值
   checkIsPressDigests(ev.getX(), ev.getY());
   //判斷是否處于選擇模式
   if (!isSelect) {
    if (isBookDigestDown == 0) {
     postLongClickPerform(0);//提交長按時(shí)間
    }
   } else {
    // 判斷是否觸摸到選擇光標(biāo)上,若是則可以拖動光標(biāo)移動
    checkCurrentMoveCursor(ev);
   }
   break;
  case MotionEvent.ACTION_MOVE:
   float move = PointF.length(ev.getX() - mTouchDownPoint.x, ev.getY() - mTouchDownPoint.y);
   if (move > moveSlop) {
    isPressInvalid = true;
   }
   if (isPressInvalid) {
    removeLongPressPerform();
    if (isSelect) {
     // 關(guān)閉彈窗(包括筆記編輯框等)
     onCloseView();
     // 移動光標(biāo)
     onMove(ev);
    } else {
     //未處于選擇模式下,相當(dāng)于一個(gè)普通的點(diǎn)擊事件
     onPress(ev);
    }
   }
   break;
  case MotionEvent.ACTION_UP:
   hasConsume = false;
   removeLongPressPerform();
   if (isSelect) {
    // -1 表示為未觸摸到光標(biāo)
    if (moveCursor == -1) {
     // 取消選擇模式
     setSelect(false);
     hasConsume = true;
    } else {
     //停止移動時(shí),會打開筆記生成彈框
     onOpenDigestsView();
    }
    moveCursor = -1;
   } else {
    if (isBookDigestDown == 1) {
     onOpenNoteView();
     hasConsume = true;
    } else if (isBookDigestDown == 2) {
     onOpenEditView();
     hasConsume = true;
    } else {
     // 模擬成一個(gè)普通的點(diǎn)擊事件,會取消當(dāng)前的選擇模式
     onPress(ev);
    }
   }
   invalidate();
   break;
  case MotionEvent.ACTION_CANCEL:
   hasConsume = false;
   removeLongPressPerform();
   break;
  default:
   break;
 }
 // 判斷選擇器是否消耗了當(dāng)前事件
 return hasConsume || isSelect;
}

當(dāng)然,筆記也要記錄當(dāng)前選擇的書籍id,章節(jié)id(或序號),文字在章節(jié)中的位置這些信息,方便定點(diǎn)跳轉(zhuǎn)。

設(shè)置——為閱讀器添磚加瓦

閱讀器設(shè)置界面

閱讀器的設(shè)置一般包括:界面亮度的調(diào)整,字體大小的調(diào)整,上下章的跳轉(zhuǎn),書籍目錄筆記和書簽的展示,翻頁動畫的更改,日夜主題的更改。當(dāng)一些設(shè)置需要閱讀器能夠在參數(shù)變化時(shí)及時(shí)響應(yīng),就得需要在設(shè)置變化時(shí)能及時(shí)更新 BookReaderView 下的各個(gè) Element 模塊。

這里我是通過一個(gè)輔助類貫穿整個(gè)閱讀器來幫助更新各個(gè)模塊,該類記錄了閱讀器內(nèi)部所有可設(shè)置的屬性,當(dāng)各個(gè)模塊被通知需要更新時(shí)重新從該類中讀取參數(shù)并設(shè)置(比如畫筆的顏色,頁面的間距,字體的大小等)。

// 摘自 PageElement 下的設(shè)置屬性變化方法
// BookSettingParams 即為記錄閱讀器設(shè)置屬性的輔助類
@Override
public void update(ReaderSettingParams params) {
  bookSettingParams = (BookSettingParams) params;
  bookHeaderElement.update(bookSettingParams);
  bookFooterElement.update(bookSettingParams);
  bookLineElement.update(bookSettingParams);
  bookImageElement.update(bookSettingParams);

  initPageElement();
}

語音朗讀——為閱讀器添加輔助功能

語音朗讀

此處的語音朗讀使用的是訊飛的TTS引擎。如何使用引入TTS我這里就不具體描述了,重要的是在TTS的 onSpeakProgress(int progress, int beginPos, int endPos) 方法中可以獲取當(dāng)前句子的朗讀進(jìn)度。

當(dāng)我們傳入一章文字時(shí),TTS會自動幫助我們分段(會以,。等標(biāo)點(diǎn)符號切割整篇文字),然后按段落來進(jìn)行朗讀。上面 progress 代表該段落在整篇文字的進(jìn)度,beginPos 代表該段落的起始字符在整篇文字的位置,endPos 代表該段落的末尾字符在整篇文字的位置。

既然能夠知道朗讀的位置,那就能知道朗讀時(shí)文字在屏幕的位置了(之前有說過 LineData 記錄了每個(gè)字符在屏幕中的位置),那剩下的就是怎么繪制的問題了。

/**
 * <p>
 * 聽書tts播放模組
 *
 * @author cpacm 2017/12/13
 */

public class BookSpeechElement extends ResElement implements SynthesizerListener {

  // .... 省略部分代碼
  
  // 從每一頁數(shù)據(jù) PageData 中的 LineData 列表中獲取要繪制的區(qū)域
  private void updateDrawRect(int startPos, int endPos) {
    if (endPos <= offsetPosition || endPos == this.endPos) return;
    this.endPos = endPos;
    this.tempPos = startPos;
    int s = this.startPos + startPos + bookPageData.getStartPos() - offsetPosition;
    int e = this.startPos + endPos + bookPageData.getStartPos() - offsetPosition;
    drawRect.clear();
    for (BookLineData line : lineData) {
      if (line.startPos > e || line.endPos <= s) continue;
      if (line.startPos <= s && line.endPos <= e) {
        Rect startRect = line.getCharArea().get(s);
        Rect endRect = line.getCharArea().get(line.endPos - 1);
        Rect rect = new Rect(startRect.left, startRect.top, endRect.right, endRect.bottom);
        drawRect.add(rect);
      }
      if (line.startPos > s && line.endPos <= e) {
        Rect startRect = line.getCharArea().get(line.startPos);
        Rect endRect = line.getCharArea().get(line.endPos - 1);
        Rect rect = new Rect(startRect.left, startRect.top, endRect.right, endRect.bottom);
        drawRect.add(rect);
      }
      if (line.startPos > s && line.endPos > e) {
        Rect startRect = line.getCharArea().get(line.startPos);
        Rect endRect = line.getCharArea().get(e);
        Rect rect = new Rect(startRect.left, startRect.top, endRect.right, endRect.bottom);
        drawRect.add(rect);
      }
      if (line.startPos <= s && line.endPos > e) {
        Rect startRect = line.getCharArea().get(s);
        Rect endRect = line.getCharArea().get(e);
        Rect rect = new Rect(startRect.left, startRect.top, endRect.right, endRect.bottom);
        drawRect.add(rect);
      }
    }
    // 刷新當(dāng)前書頁
    bookReaderView.flashCurrentPageSnapshot();
  }


  @Override
  public void draw(Canvas canvas) {
    if (!isSpeaking()) return;
    for (Rect rect : drawRect) {
      canvas.drawLine(rect.left, rect.bottom, rect.right, rect.bottom, paint);
    }
  }

  @Override
  public void destroy() {
    exitTts();
  }
  
  /*################## 語音合成的回調(diào) ###################*/
  @Override
  public void onSpeakBegin() {}

  @Override
  public void onBufferProgress(int progress, int beginPos, int endPos, String info) { }

  @Override
  public void onSpeakPaused() {}

  @Override
  public void onSpeakResumed() {}

  @Override
  public void onSpeakProgress(int progress, int beginPos, int endPos) {
    // 根據(jù)朗讀的進(jìn)度更新UI
    updateDrawRect(beginPos, endPos);
  }

  @Override
  public void onCompleted(SpeechError speechError) {}

  @Override
  public void onEvent(int i, int i1, int i2, Bundle bundle) {}
}

總結(jié)

首先聲明一點(diǎn),整篇文章只是闡述了我自己從零開始做書籍閱讀器時(shí)一些思路和使用的一些技巧,并沒有覆蓋到閱讀器的各個(gè)角落。如果你想要自己實(shí)現(xiàn)一款閱讀器,那你必須要有扎實(shí)的基礎(chǔ)知識,比如View的繪制流程和事件分發(fā)流程,Canvas的繪圖知識等,這篇文章也只是給大家提個(gè)思路而已。如果有問題或者新的想法歡迎交流!

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android ActionBar制作時(shí)鐘實(shí)例解析

    Android ActionBar制作時(shí)鐘實(shí)例解析

    這篇文章主要為大家詳細(xì)介紹了Android ActionBar制作時(shí)鐘的實(shí)現(xiàn)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • Android自定義View實(shí)現(xiàn)公交成軌跡圖

    Android自定義View實(shí)現(xiàn)公交成軌跡圖

    這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)公交成軌跡圖,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • Android MIUI通知類短信權(quán)限的坑

    Android MIUI通知類短信權(quán)限的坑

    本篇文章主要介紹了Android MIUI通知類短信權(quán)限的坑,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-03-03
  • Android 新手引導(dǎo)蒙層效果實(shí)現(xiàn)代碼示例

    Android 新手引導(dǎo)蒙層效果實(shí)現(xiàn)代碼示例

    本篇文章主要介紹了Android 新手引導(dǎo)蒙層效果實(shí)現(xiàn)代碼示例,具有一定的參考價(jià)值,有興趣的可以了解一下。
    2017-01-01
  • Android studio2.3.3升級到3.1.2坑(小記)

    Android studio2.3.3升級到3.1.2坑(小記)

    這篇文章主要介紹了Android studio2.3.3升級3.1.2坑(小記),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-09-09
  • Android自定義view實(shí)現(xiàn)輸入框效果

    Android自定義view實(shí)現(xiàn)輸入框效果

    這篇文章主要為大家詳細(xì)介紹了Android自定義view實(shí)現(xiàn)輸入框效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • Android實(shí)現(xiàn)雅虎新聞?wù)虞d視差動畫效果

    Android實(shí)現(xiàn)雅虎新聞?wù)虞d視差動畫效果

    這篇文章主要介紹了Android實(shí)現(xiàn)雅虎新聞?wù)虞d視差動畫效果,通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08
  • 基于Viewpager2實(shí)現(xiàn)登錄注冊引導(dǎo)頁面

    基于Viewpager2實(shí)現(xiàn)登錄注冊引導(dǎo)頁面

    這篇文章主要為大家詳細(xì)介紹了基于Viewpager2實(shí)現(xiàn)登錄注冊引導(dǎo)頁面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • 使用Chrome瀏覽器調(diào)試Android App詳解

    使用Chrome瀏覽器調(diào)試Android App詳解

    這篇文章主要介紹了使用Chrome瀏覽器調(diào)試Android App詳解,本網(wǎng)講解了使用Facebook開源Stetho實(shí)現(xiàn)在Chrome中調(diào)試Android App中,需要的朋友可以參考下
    2015-05-05
  • Android開發(fā)圖片水平旋轉(zhuǎn)180度方法

    Android開發(fā)圖片水平旋轉(zhuǎn)180度方法

    今天小編就為大家分享一篇Android開發(fā)圖片水平旋轉(zhuǎn)180度方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08

最新評論

抚顺县| 保康县| 贵溪市| 元朗区| 江华| 丘北县| 通渭县| 十堰市| 彭山县| 六盘水市| 信丰县| 阿荣旗| 永清县| 丹阳市| 南城县| 阿拉尔市| 乐至县| 永嘉县| 长沙市| 高雄县| 潍坊市| 长泰县| 蛟河市| 枝江市| 彭水| 峨眉山市| 商南县| 瓦房店市| 永川市| 聊城市| 阳春市| 吉木乃县| 河曲县| 章丘市| 星子县| 安西县| 麻江县| 奉贤区| 洞口县| 梅州市| 吉木萨尔县|