WebView實現長按儲存圖片 長按識別二維碼

大頭呆發表於2019-03-04

先來簡單說一下本文所要實現的功能:使用者在瀏覽網頁的時候,長按某一區域,識別如果是圖片,則彈出彈框,出現儲存圖片的功能。同時識別圖片是否是二維碼,如果是則在彈框中追加識別二維碼功能。

細節上:儲存圖片的彈框要顯示在手指長按的位置;選擇圖片儲存後,可以讓使用者直接去相簿檢視;選擇識別二維碼,判斷是是不是網址,是的話可以讓使用者選擇複製或訪問,否則可以讓使用者選擇複製或搜尋。

然後再來看一下效果圖:

儲存圖片
WebView實現長按儲存圖片 長按識別二維碼
識別包含普通文字的二維碼:
WebView實現長按儲存圖片 長按識別二維碼
識別包含網址的二維碼:
WebView實現長按儲存圖片 長按識別二維碼

上述功能所用到的類和庫:

  • 獲得長按內容:WebView.HitTestResult
  • 彈框列表:DialogFragment
  • 圖片下載:Glide
  • 二維碼識別:Zxing

實現要點

記錄長按位置

繼承WebView記錄觸控位置:

  @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        touchX = (int) event.getRawX();
        touchY = (int) event.getRawY();
        return super.onInterceptTouchEvent(event);
    }
複製程式碼

彈框我選擇DialogFragment而不是poupwindow的原因是poupwindow的顯示通常需要依託另一個View,而且在7.0以上有相容問題。
判斷長按位置的內容型別是否是圖片:

獲取圖片資訊

     setOnLongClickListener(new View.OnLongClickListener() {

            public boolean onLongClick(View v) {
                WebView.HitTestResult result = getHitTestResult();
                if (null == result)
                    return false;
                int type = result.getType();
                switch (type) {
                    case WebView.HitTestResult.EDIT_TEXT_TYPE: // 選中的文字型別
                        break;
                    case WebView.HitTestResult.PHONE_TYPE: // 處理撥號
                        break;
                    case WebView.HitTestResult.EMAIL_TYPE: // 處理Email
                        break;
                    case WebView.HitTestResult.GEO_TYPE: //  地圖型別
                        break;
                    case WebView.HitTestResult.SRC_ANCHOR_TYPE: // 超連結
                        break;
                    case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE: // 帶有連結的圖片型別
                    case WebView.HitTestResult.IMAGE_TYPE: // 處理長按圖片的選單項
                        String url = result.getExtra();
                        if (mOnSelectItemListener != null && url != null && URLUtil.isValidUrl(url)) {
                            mOnSelectItemListener.onSelected(touchX, touchY, result.getType(), url);
                        }
                        return true;
                    case WebView.HitTestResult.UNKNOWN_TYPE: //未知
                        break;
                }
                return false;
            }
        });
複製程式碼

在手指長按位置處彈出彈框

HitTestResult是一個實體類,只記錄兩個資訊:當選選擇內容的型別和內容的具體值。可以看到通過WebView.HitTestResult,我們可以獲得除了圖片外的很多內容型別。當然這裡我們只需要判斷是否是圖片就好了,然後將長按位置和url一起回撥給外層。在手指長按處顯示彈框,主要就是DialogFragment顯示位置的設定了:

 public void onStart() {
        super.onStart();
        Dialog dialog = getDialog();
        if (dialog != null) {
            Window window = dialog.getWindow();
            if (window != null) {
                WindowManager.LayoutParams lp = window.getAttributes();
                window.setGravity(Gravity.LEFT | Gravity.TOP);
                lp.x = LocationX;//橫座標位置
                lp.y = LocationY;//縱座標位置
                lp.width = UIHelper.dip2px(100);
                lp.dimAmount = 0.0f;//外層背景透明,預設變暗
                lp.width = ViewGroup.LayoutParams.WRAP_CONTENT;
                lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
                window.setAttributes(lp);
                window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));//內部背景透明
            }
        }
    }
複製程式碼

儲存到相簿

利用Glide下載圖片,Glide自帶預載入和圖片快取功能,不需要每次都從網路中下載:

GlideApp.with(appContext).asFile().load(url).submit().get();
複製程式碼

可以在長按識別出圖片的時候就行預載入:

 GlideApp.with(appContext).asBitmap().load(url).preload();
複製程式碼

將圖片儲存在相簿:

 public static void displayToGallery(Context context, File photoFile) {
        if (photoFile == null || !photoFile.exists()) {
            return;
        }
        String photoPath = photoFile.getAbsolutePath();
        String photoName = photoFile.getName();
        // 把檔案插入到系統相簿
        try {
            ContentResolver contentResolver = context.getContentResolver();
            MediaStore.Images.Media.insertImage(contentResolver, photoPath, photoName, null);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 最後通知相簿更新
        context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + photoPath)));
    }
複製程式碼

識別圖片中的二維碼

顯示彈框的同時還要判斷圖片是否包含二維碼,這部分就是Zxing自帶的功能,所以程式碼就不貼了。注意不應該等是Zxing判斷是不是二維碼後再顯示彈框,因為這部分操作耗時可能比較長(見圖二)。應當在識別二維碼內容後再去更新彈框列表的內容。

總結

總體來說這個功能實現注意的地方還是挺多的,好在都不復雜。當然本例還存在待優化的地方,以及實現更高階的功能,比如以圖搜圖,檢視大圖功能,也可以利用WebView.HitTestResult對獲取到其他型別的內容進行處理,限於篇幅就不再展開了。
最後貼下本專案Github地址,對WebView感興趣的可以瞭解下:

Github

相關文章