实例介绍
【实例简介】
【实例截图】
【实例截图】
【核心代码】
package com.brandontate.androidwebviewselection; import org.json.JSONException; import org.json.JSONObject; import com.blahti.drag.DragController; import com.blahti.drag.DragLayer; import com.blahti.drag.DragListener; import com.blahti.drag.DragSource; import com.blahti.drag.MyAbsoluteLayout; import net.londatiga.android.ActionItem; import net.londatiga.android.QuickAction; import net.londatiga.android.QuickAction.OnDismissListener; import android.content.Context; import android.graphics.Rect; import android.graphics.Region; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; import android.view.Display; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.view.WindowManager; import android.webkit.WebView; import android.widget.ImageView; public class BTWebView extends WebView implements TextSelectionJavascriptInterfaceListener, OnTouchListener, OnLongClickListener, OnDismissListener, DragListener{ /** The logging tag. */ private static final String TAG = "BTWebView"; /** Context. */ protected Context ctx; /** The context menu. */ private QuickAction mContextMenu; /** The drag layer for selection. */ private DragLayer mSelectionDragLayer; /** The drag controller for selection. */ private DragController mDragController; /** The start selection handle. */ private ImageView mStartSelectionHandle; /** the end selection handle. */ private ImageView mEndSelectionHandle; /** The selection bounds. */ private Rect mSelectionBounds = null; /** The previously selected region. */ protected Region lastSelectedRegion = null; /** The selected range. */ protected String selectedRange = ""; /** The selected text. */ protected String selectedText = ""; /** Javascript interface for catching text selection. */ protected TextSelectionJavascriptInterface textSelectionJSInterface = null; /** Selection mode flag. */ protected boolean inSelectionMode = false; /** Flag to stop from showing context menu twice. */ protected boolean contextMenuVisible = false; /** The current content width. */ protected int contentWidth = 0; /** Identifier for the selection start handle. */ private final int SELECTION_START_HANDLE = 0; /** Identifier for the selection end handle. */ private final int SELECTION_END_HANDLE = 1; /** Last touched selection handle. */ private int mLastTouchedSelectionHandle = -1; public BTWebView(Context context) { super(context); this.ctx = context; this.setup(context); } public BTWebView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.ctx = context; this.setup(context); } public BTWebView(Context context, AttributeSet attrs) { super(context, attrs); this.ctx = context; this.setup(context); } //***************************************************** //* //* Touch Listeners //* //***************************************************** private boolean mScrolling = false; private float mScrollDiffY = 0; private float mLastTouchY = 0; private float mScrollDiffX = 0; private float mLastTouchX = 0; @Override public boolean onTouch(View v, MotionEvent event) { float xPoint = getDensityIndependentValue(event.getX(), ctx) / getDensityIndependentValue(this.getScale(), ctx); float yPoint = getDensityIndependentValue(event.getY(), ctx) / getDensityIndependentValue(this.getScale(), ctx); // TODO: Need to update this to use this.getScale() as a factor. if(event.getAction() == MotionEvent.ACTION_DOWN){ String startTouchUrl = String.format("javascript:android.selection.startTouch(%f, %f);", xPoint, yPoint); mLastTouchX = xPoint; mLastTouchY = yPoint; this.loadUrl(startTouchUrl); // Flag scrolling for first touch //if(!this.isInSelectionMode()) //mScrolling = true; } else if(event.getAction() == MotionEvent.ACTION_UP){ // Check for scrolling flag if(!mScrolling){ this.endSelectionMode(); } mScrollDiffX = 0; mScrollDiffY = 0; mScrolling = false; } else if(event.getAction() == MotionEvent.ACTION_MOVE){ mScrollDiffX = (xPoint - mLastTouchX); mScrollDiffY = (yPoint - mLastTouchY); mLastTouchX = xPoint; mLastTouchY = yPoint; // Only account for legitimate movement. if(Math.abs(mScrollDiffX) > 10 || Math.abs(mScrollDiffY) > 10){ mScrolling = true; } } // If this is in selection mode, then nothing else should handle this touch return false; } @Override public boolean onLongClick(View v){ // Tell the javascript to handle this if not in selection mode //if(!this.isInSelectionMode()){ this.loadUrl("javascript:android.selection.longTouch();"); mScrolling = true; //} // Don't let the webview handle it return true; } //***************************************************** //* //* Setup //* //***************************************************** /** * Setups up the web view. * @param context */ protected void setup(Context context){ // On Touch Listener this.setOnLongClickListener(this); this.setOnTouchListener(this); // Webview setup this.getSettings().setJavaScriptEnabled(true); this.getSettings().setJavaScriptCanOpenWindowsAutomatically(true); this.getSettings().setPluginsEnabled(true); // Zoom out fully //this.getSettings().setLoadWithOverviewMode(true); //this.getSettings().setUseWideViewPort(true); // Javascript interfaces this.textSelectionJSInterface = new TextSelectionJavascriptInterface(context, this); this.addJavascriptInterface(this.textSelectionJSInterface, this.textSelectionJSInterface.getInterfaceName()); // Create the selection handles createSelectionLayer(context); // Set to the empty region Region region = new Region(); region.setEmpty(); this.lastSelectedRegion = region; // Load up the android asset file String filePath = "file:///android_asset/content.html"; // Load the url this.loadUrl(filePath); } //***************************************************** //* //* Selection Layer Handling //* //***************************************************** /** * Creates the selection layer. * * @param context */ protected void createSelectionLayer(Context context){ LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); this.mSelectionDragLayer = (DragLayer) inflater.inflate(R.layout.selection_drag_layer, null); // Make sure it's filling parent this.mDragController = new DragController(context); this.mDragController.setDragListener(this); this.mDragController.addDropTarget(mSelectionDragLayer); this.mSelectionDragLayer.setDragController(mDragController); this.mStartSelectionHandle = (ImageView) this.mSelectionDragLayer.findViewById(R.id.startHandle); this.mStartSelectionHandle.setTag(new Integer(SELECTION_START_HANDLE)); this.mEndSelectionHandle = (ImageView) this.mSelectionDragLayer.findViewById(R.id.endHandle); this.mEndSelectionHandle.setTag(new Integer(SELECTION_END_HANDLE)); OnTouchListener handleTouchListener = new OnTouchListener(){ @Override public boolean onTouch(View v, MotionEvent event) { boolean handledHere = false; final int action = event.getAction(); // Down event starts drag for handle. if (action == MotionEvent.ACTION_DOWN) { handledHere = startDrag (v); mLastTouchedSelectionHandle = (Integer) v.getTag(); } return handledHere; } }; this.mStartSelectionHandle.setOnTouchListener(handleTouchListener); this.mEndSelectionHandle.setOnTouchListener(handleTouchListener); } /** * Starts selection mode on the UI thread */ private Handler startSelectionModeHandler = new Handler(){ public void handleMessage(Message m){ if(mSelectionBounds == null) return; addView(mSelectionDragLayer); drawSelectionHandles(); int contentHeight = (int) Math.ceil(getDensityDependentValue(getContentHeight(), ctx)); // Update Layout Params ViewGroup.LayoutParams layerParams = mSelectionDragLayer.getLayoutParams(); layerParams.height = contentHeight; layerParams.width = contentWidth; mSelectionDragLayer.setLayoutParams(layerParams); } }; /** * Starts selection mode. * * @param selectionBounds */ public void startSelectionMode(){ this.startSelectionModeHandler.sendEmptyMessage(0); } // Ends selection mode on the UI thread private Handler endSelectionModeHandler = new Handler(){ public void handleMessage(Message m){ removeView(mSelectionDragLayer); if(getParent() != null && mContextMenu != null && contextMenuVisible){ // This will throw an error if the webview is being redrawn. // No error handling needed, just need to stop the crash. try{ mContextMenu.dismiss(); } catch(Exception e){ } } mSelectionBounds = null; mLastTouchedSelectionHandle = -1; loadUrl("javascript: android.selection.clearSelection();"); } }; /** * Ends selection mode. */ public void endSelectionMode(){ this.endSelectionModeHandler.sendEmptyMessage(0); } /** * Calls the handler for drawing the selection handles. */ private void drawSelectionHandles(){ this.drawSelectionHandlesHandler.sendEmptyMessage(0); } /** * Handler for drawing the selection handles on the UI thread. */ private Handler drawSelectionHandlesHandler = new Handler(){ public void handleMessage(Message m){ MyAbsoluteLayout.LayoutParams startParams = (com.blahti.drag.MyAbsoluteLayout.LayoutParams) mStartSelectionHandle.getLayoutParams(); startParams.x = (int) (mSelectionBounds.left - mStartSelectionHandle.getDrawable().getIntrinsicWidth()); startParams.y = (int) (mSelectionBounds.top - mStartSelectionHandle.getDrawable().getIntrinsicHeight()); // Stay on screen. startParams.x = (startParams.x < 0) ? 0 : startParams.x; startParams.y = (startParams.y < 0) ? 0 : startParams.y; mStartSelectionHandle.setLayoutParams(startParams); MyAbsoluteLayout.LayoutParams endParams = (com.blahti.drag.MyAbsoluteLayout.LayoutParams) mEndSelectionHandle.getLayoutParams(); endParams.x = (int) mSelectionBounds.right; endParams.y = (int) mSelectionBounds.bottom; // Stay on screen endParams.x = (endParams.x < 0) ? 0 : endParams.x; endParams.y = (endParams.y < 0) ? 0 : endParams.y; mEndSelectionHandle.setLayoutParams(endParams); } }; /** * Checks to see if this view is in selection mode. * @return */ public boolean isInSelectionMode(){ return this.mSelectionDragLayer.getParent() != null; } //***************************************************** //* //* DragListener Methods //* //***************************************************** /** * Start dragging a view. * */ private boolean startDrag (View v) { // Let the DragController initiate a drag-drop sequence. // I use the dragInfo to pass along the object being dragged. // I'm not sure how the Launcher designers do this. Object dragInfo = v; mDragController.startDrag (v, mSelectionDragLayer, dragInfo, DragController.DRAG_ACTION_MOVE); return true; } @Override public void onDragStart(DragSource source, Object info, int dragAction) { // TODO Auto-generated method stub } @Override public void onDragEnd() { // TODO Auto-generated method stub MyAbsoluteLayout.LayoutParams startHandleParams = (MyAbsoluteLayout.LayoutParams) this.mStartSelectionHandle.getLayoutParams(); MyAbsoluteLayout.LayoutParams endHandleParams = (MyAbsoluteLayout.LayoutParams) this.mEndSelectionHandle.getLayoutParams(); float scale = getDensityIndependentValue(this.getScale(), ctx); float startX = startHandleParams.x - this.getScrollX(); float startY = startHandleParams.y - this.getScrollY(); float endX = endHandleParams.x - this.getScrollX(); float endY = endHandleParams.y - this.getScrollY(); startX = getDensityIndependentValue(startX, ctx) / scale; startY = getDensityIndependentValue(startY, ctx) / scale; endX = getDensityIndependentValue(endX, ctx) / scale; endY = getDensityIndependentValue(endY, ctx) / scale; if(mLastTouchedSelectionHandle == SELECTION_START_HANDLE && startX > 0 && startY > 0){ String saveStartString = String.format("javascript: android.selection.setStartPos(%f, %f);", startX, startY); this.loadUrl(saveStartString); } if(mLastTouchedSelectionHandle == SELECTION_END_HANDLE && endX > 0 && endY > 0){ String saveEndString = String.format("javascript: android.selection.setEndPos(%f, %f);", endX, endY); this.loadUrl(saveEndString); } } //***************************************************** //* //* Context Menu Creation //* //***************************************************** /** * Shows the context menu using the given region as an anchor point. * @param region */ private void showContextMenu(Rect displayRect){ // Don't show this twice if(this.contextMenuVisible){ return; } // Don't use empty rect //if(displayRect.isEmpty()){ if(displayRect.right <= displayRect.left){ return; } //Copy action item ActionItem buttonOne = new ActionItem(); buttonOne.setTitle("Button 1"); buttonOne.setActionId(1); buttonOne.setIcon(getResources().getDrawable(R.drawable.menu_search)); //Highlight action item ActionItem buttonTwo = new ActionItem(); buttonTwo.setTitle("Button 2"); buttonTwo.setActionId(2); buttonTwo.setIcon(getResources().getDrawable(R.drawable.menu_info)); ActionItem buttonThree = new ActionItem(); buttonThree.setTitle("Button 3"); buttonThree.setActionId(3); buttonThree.setIcon(getResources().getDrawable(R.drawable.menu_eraser)); // The action menu mContextMenu = new QuickAction(this.getContext()); mContextMenu.setOnDismissListener(this); // Add buttons mContextMenu.addActionItem(buttonOne); mContextMenu.addActionItem(buttonTwo); mContextMenu.addActionItem(buttonThree); //setup the action item click listener mContextMenu.setOnActionItemClickListener(new QuickAction.OnActionItemClickListener() { @Override public void onItemClick(QuickAction source, int pos, int actionId) { // TODO Auto-generated method stub if (actionId == 1) { // Do Button 1 stuff Log.i(TAG, "Hit Button 1"); } else if (actionId == 2) { // Do Button 2 stuff Log.i(TAG, "Hit Button 2"); } else if (actionId == 3) { // Do Button 3 stuff Log.i(TAG, "Hit Button 3"); } contextMenuVisible = false; } }); this.contextMenuVisible = true; mContextMenu.show(this, displayRect); } //***************************************************** //* //* OnDismiss Listener //* //***************************************************** /** * Clears the selection when the context menu is dismissed. */ public void onDismiss(){ //clearSelection(); this.contextMenuVisible = false; } //***************************************************** //* //* Text Selection Javascript Interface Listener //* //***************************************************** /** * Shows/updates the context menu based on the range */ public void tsjiJSError(String error){ Log.e(TAG, "JSError: " error); } /** * The user has started dragging the selection handles. */ public void tsjiStartSelectionMode(){ this.startSelectionMode(); } /** * The user has stopped dragging the selection handles. */ public void tsjiEndSelectionMode(){ this.endSelectionMode(); } /** * The selection has changed * @param range * @param text * @param handleBounds * @param menuBounds * @param showHighlight * @param showUnHighlight */ public void tsjiSelectionChanged(String range, String text, String handleBounds, String menuBounds){ try { JSONObject selectionBoundsObject = new JSONObject(handleBounds); float scale = getDensityIndependentValue(this.getScale(), ctx); Rect handleRect = new Rect(); handleRect.left = (int) (getDensityDependentValue(selectionBoundsObject.getInt("left"), getContext()) * scale); handleRect.top = (int) (getDensityDependentValue(selectionBoundsObject.getInt("top"), getContext()) * scale); handleRect.right = (int) (getDensityDependentValue(selectionBoundsObject.getInt("right"), getContext()) * scale); handleRect.bottom = (int) (getDensityDependentValue(selectionBoundsObject.getInt("bottom"), getContext()) * scale); this.mSelectionBounds = handleRect; this.selectedRange = range; this.selectedText = text; JSONObject menuBoundsObject = new JSONObject(menuBounds); Rect displayRect = new Rect(); displayRect.left = (int) (getDensityDependentValue(menuBoundsObject.getInt("left"), getContext()) * scale); displayRect.top = (int) (getDensityDependentValue(menuBoundsObject.getInt("top") - 25, getContext()) * scale); displayRect.right = (int) (getDensityDependentValue(menuBoundsObject.getInt("right"), getContext()) * scale); displayRect.bottom = (int) (getDensityDependentValue(menuBoundsObject.getInt("bottom") 25, getContext()) * scale); if(!this.isInSelectionMode()){ this.startSelectionMode(); } // This will send the menu rect this.showContextMenu(displayRect); drawSelectionHandles(); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * Receives the content width for the page. */ public void tsjiSetContentWidth(float contentWidth){ this.contentWidth = (int) this.getDensityDependentValue(contentWidth, ctx); } //***************************************************** //* //* Density Conversion //* //***************************************************** /** * Returns the density dependent value of the given float * @param val * @param ctx * @return */ public float getDensityDependentValue(float val, Context ctx){ // Get display from context Display display = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); // Calculate min bound based on metrics DisplayMetrics metrics = new DisplayMetrics(); display.getMetrics(metrics); return val * (metrics.densityDpi / 160f); //return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, val, metrics); } /** * Returns the density independent value of the given float * @param val * @param ctx * @return */ public float getDensityIndependentValue(float val, Context ctx){ // Get display from context Display display = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); // Calculate min bound based on metrics DisplayMetrics metrics = new DisplayMetrics(); display.getMetrics(metrics); return val / (metrics.densityDpi / 160f); //return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, val, metrics); } }
好例子网口号:伸出你的我的手 — 分享!
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论