Android webView和js交互
来源:互联网 发布:苹果软件推广 编辑:程序博客网 时间:2024/04/29 20:52
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <WebView android:id="@+id/webview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="9" /></LinearLayout>
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <!-- TODO 默认占位图 --> <wst.webview.ZoomableImageView android:id="@+id/show_webimage_imageview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="matrix" android:src="@drawable/ic_launcher" /> <TextView android:id="@+id/show_webimage_imagepath_textview" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:textColor="#ffff0000" /></LinearLayout>
package wst.webview;import android.annotation.SuppressLint;import android.app.Activity;import android.content.Context;import android.content.Intent;import android.graphics.Bitmap;import android.os.Bundle;import android.webkit.WebView;import android.webkit.WebViewClient;@SuppressLint({ "SetJavaScriptEnabled", "JavascriptInterface" })public class MainActivity extends Activity {private WebView contentWebView = null;@SuppressLint("SetJavaScriptEnabled")@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);contentWebView = (WebView) findViewById(R.id.webview);// 启用javascriptcontentWebView.getSettings().setJavaScriptEnabled(true);// 随便找了个带图片的网站contentWebView.loadUrl("http://www.sina.com.cn/");// 添加js交互接口类,并起别名 imagelistnercontentWebView.addJavascriptInterface(new scriptInterface(this), "imagelistner");contentWebView.setWebViewClient(new MyWebViewClient());}// 注入js函数监听@android.webkit.JavascriptInterfaceprivate void addImageClickListner() {// 这段js函数的功能就是,遍历所有的img几点,并添加onclick函数,在还是执行的时候调用本地接口传递url过去 contentWebView.loadUrl("javascript:(function(){" +"var objs = document.getElementsByTagName(\"img\"); " + "for(var i=0;i<objs.length;i++) " + "{"+ " objs[i].onclick=function() " + " { " + " window.imagelistner.openImage(this.src); " + " } " + "}" + "})()");}// js通信接口 class scriptInterface {private Context context;public scriptInterface(Context context) {this.context = context;}@android.webkit.JavascriptInterfacepublic void openImage(String img) {System.out.println(img);//Intent intent = new Intent();intent.putExtra("image", img);intent.setClass(context, ShowWebImageActivity.class);context.startActivity(intent);System.out.println(img);}}// 监听private class MyWebViewClient extends WebViewClient {@Overridepublic boolean shouldOverrideUrlLoading(WebView view, String url) {return super.shouldOverrideUrlLoading(view, url);}@Overridepublic void onPageFinished(WebView view, String url) {view.getSettings().setJavaScriptEnabled(true);super.onPageFinished(view, url);// html加载完成之后,添加监听图片的点击js函数addImageClickListner();}@Overridepublic void onPageStarted(WebView view, String url, Bitmap favicon) {view.getSettings().setJavaScriptEnabled(true);super.onPageStarted(view, url, favicon);}@Overridepublic void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {super.onReceivedError(view, errorCode, description, failingUrl);}}}
package wst.webview;public interface OnImageTouchedListener {void onImageTouched();}
package wst.webview;import java.io.IOException;import java.io.InputStream;import java.net.MalformedURLException;import java.net.URL;import java.net.URLConnection;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.drawable.Drawable;import android.os.AsyncTask;import android.os.Bundle;import android.widget.TextView;public class ShowWebImageActivity extends Activity {private TextView imageTextView = null;private String imagePath = null;private ZoomableImageView imageView = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.show_webimage);this.imagePath = getIntent().getStringExtra("image");this.imageTextView = (TextView) findViewById(R.id.show_webimage_imagepath_textview);imageTextView.setText(this.imagePath);imageView = (ZoomableImageView) findViewById(R.id.show_webimage_imageview);//try {//imageView.setImageBitmap(((BitmapDrawable) ShowWebImageActivity.loadImageFromUrl(this.imagePath)).getBitmap());//} catch (IOException e) {//e.printStackTrace();//}LoadImageAsyncTask task = new LoadImageAsyncTask();task.setImageView(imageView); task.execute(this.imagePath); // 执行任务,参数与 doInBackground(String... params) 方法参数一致}public static Drawable loadImageFromUrl(String url) throws IOException {URL m = new URL(url);InputStream i = (InputStream) m.getContent();Drawable d = Drawable.createFromStream(i, "src");return d;} /** * 异步加载图片 * */ public class LoadImageAsyncTask extends AsyncTask<String, Integer, Bitmap> { private ZoomableImageView imageView; @Override protected void onPostExecute(Bitmap bitmap) { if (null != imageView) { imageView.setImageBitmap(bitmap); } } // 设置图片视图实例 public void setImageView(ZoomableImageView image) { this.imageView = image; } @Override protected Bitmap doInBackground(String... params) { Bitmap bitmap = GetBitmapByUrl(params[0]); // 调用前面 ApacheUtility 类的方法 return bitmap; } } /** * 获取图片流 * * @param uri 图片地址 * @return * @throws MalformedURLException */ public static InputStream GetImageByUrl(String uri) throws MalformedURLException { URL url = new URL(uri); URLConnection conn; InputStream is; try { conn = url.openConnection(); conn.connect(); is = conn.getInputStream(); // 或者用如下方法 // is=(InputStream)url.getContent(); return is; } catch (IOException e) { e.printStackTrace(); } return null; } /** * 获取Bitmap * * @param uri 图片地址 * @return */ public static Bitmap GetBitmapByUrl(String uri) { Bitmap bitmap; InputStream is; try { is = GetImageByUrl(uri); bitmap = BitmapFactory.decodeStream(is); is.close(); return bitmap; } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } /** * 获取Drawable * * @param uri 图片地址 * @return */ public static Drawable GetDrawableByUrl(String uri) { Drawable drawable; InputStream is; try { is = GetImageByUrl(uri); drawable= Drawable.createFromStream(is, "src"); is.close(); return drawable; } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; }}
package wst.webview;import android.annotation.SuppressLint;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.Paint;import android.os.Build;import android.os.SystemClock;import android.util.AttributeSet;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.ScaleGestureDetector;import android.view.View;import android.view.animation.Animation;import android.view.animation.TranslateAnimation;@SuppressLint("NewApi")public class ZoomableImageView extends View {// Staticsstatic final float sPanRate = 7;static final float sScaleRate = 1.25F;static final int sPaintDelay = 250;static final int sAnimationDelay = 500;// This is the base transformation which is used to show the image// initially. The current computation for this shows the image in// it's entirety, letterboxing as needed. One could chose to// show the image as cropped instead. //// This matrix is recomputed when we go from the thumbnail image to// the full size image.private Matrix mBaseMatrix = new Matrix();// This is the supplementary transformation which reflects what // the user has done in terms of zooming and panning.//// This matrix remains the same when we go from the thumbnail image// to the full size image.private Matrix mSuppMatrix = new Matrix();// This is the final matrix which is computed as the concatentation// of the base matrix and the supplementary matrix.private Matrix mDisplayMatrix = new Matrix();// A replacement ImageView matrixprivate Matrix mMatrix = new Matrix();// Used to filter the bitmaps when hardware acceleration is not enabledprivate Paint mPaint;// Temporary buffer used for getting the values out of a matrix.private float[] mMatrixValues = new float[9];// The current bitmap being displayed.private Bitmap mBitmap;// Dimensions for the viewprivate int mThisWidth = -1, mThisHeight = -1;// The max zoom for the view, determined programaticallyprivate float mMaxZoom;// If not null, calls setImageBitmap when onLayout is triggeredprivate Runnable mOnLayoutRunnable = null;// Stacked to the internal queue to invalidate the viewprivate Runnable mRefresh = null;// Stacked to the internal queue to scroll the viewprivate Runnable mFling = null;// The time of the last draw operationprivate double mLastDraw = 0;// Scale and gesture listeners for the viewprivate ScaleGestureDetector mScaleDetector;private GestureDetector mGestureDetector;// Single tap listenerprivate OnImageTouchedListener mImageTouchedListener;// Programatic entry pointpublic ZoomableImageView(Context context) {super(context);init( context );}// Set the single tap listenerpublic void setOnImageTouchedListener( OnImageTouchedListener listener ){this.mImageTouchedListener = listener;}// XML entry pointpublic ZoomableImageView(Context context, AttributeSet attrs) {super(context, attrs);init( context );}// Setup the viewprivate void init( Context context) {mPaint = new Paint();mPaint.setDither(true);mPaint.setFilterBitmap(true);mPaint.setAntiAlias(true);// Setup the refresh runnablemRefresh = new Runnable() {@Overridepublic void run() {postInvalidate();}};// Setup the gesture and scale listenersmScaleDetector = new ScaleGestureDetector( context, new ScaleListener() );mGestureDetector = new GestureDetector(context, new MyGestureListener());// Force hardware accelerationif( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB )setLayerType(View.LAYER_TYPE_HARDWARE, null);}// Get the bitmap for the viewpublic Bitmap getImageBitmap(){return mBitmap;}// Free the bitmaps and matricespublic void clear(){if(mBitmap!=null)mBitmap = null;}// When the layout is calculated, set the @Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);mThisWidth = right - left;mThisHeight = bottom - top;Runnable r = mOnLayoutRunnable;if (r != null) {mOnLayoutRunnable = null;r.run();}if (mBitmap != null) {setBaseMatrix(mBitmap, mBaseMatrix);setImageMatrix(getImageViewMatrix());}}// Translate a given point through a given matrix.static private void translatePoint(Matrix matrix, float [] xy) {matrix.mapPoints(xy);}// Identical to the setImageMatrix method in ImageViewpublic void setImageMatrix(Matrix m){if (m != null && m.isIdentity()) {m = null;}// don't invalidate unless we're actually changing our matrixif (m == null && !this.mMatrix.isIdentity() || m != null && !this.mMatrix.equals(m)) {this.mMatrix.set(m);invalidate();}}// Sets the bitmap for the image and resets the basepublic void setImageBitmap(final Bitmap bitmap) {final int viewWidth = getWidth();if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && bitmap!=null && bitmap.getHeight()>1800 )setLayerType(View.LAYER_TYPE_SOFTWARE, null);if (viewWidth <= 0) {mOnLayoutRunnable = new Runnable() {public void run() {setImageBitmap(bitmap);}};return;}if (bitmap != null) {setBaseMatrix(bitmap, mBaseMatrix);this.mBitmap = bitmap;} else {mBaseMatrix.reset();this.mBitmap = bitmap;}mSuppMatrix.reset();setImageMatrix(getImageViewMatrix());mMaxZoom = maxZoom();// Set the image to fit the screenzoomTo(zoomDefault());}// Unchanged from ImageViewTouchBase// Center as much as possible in one or both axis. Centering is// defined as follows: if the image is scaled down below the // view's dimensions then center it (literally). If the image// is scaled larger than the view and is translated out of view// then translate it back into view (i.e. eliminate black bars).protected void center(boolean vertical, boolean horizontal, boolean animate) {if (mBitmap == null)return;Matrix m = getImageViewMatrix();float [] topLeft = new float[] { 0, 0 };float [] botRight = new float[] { mBitmap.getWidth(), mBitmap.getHeight() };translatePoint(m, topLeft);translatePoint(m, botRight);float height = botRight[1] - topLeft[1];float width = botRight[0] - topLeft[0];float deltaX = 0, deltaY = 0;if (vertical) {int viewHeight = getHeight();if (height < viewHeight) {deltaY = (viewHeight - height)/2 - topLeft[1];} else if (topLeft[1] > 0) {deltaY = -topLeft[1];} else if (botRight[1] < viewHeight) {deltaY = getHeight() - botRight[1];}}if (horizontal) {int viewWidth = getWidth();if (width < viewWidth) {deltaX = (viewWidth - width)/2 - topLeft[0];} else if (topLeft[0] > 0) {deltaX = -topLeft[0];} else if (botRight[0] < viewWidth) {deltaX = viewWidth - botRight[0];}}postTranslate(deltaX, deltaY);if (animate) {Animation a = new TranslateAnimation(-deltaX, 0, -deltaY, 0);a.setStartTime(SystemClock.elapsedRealtime());a.setDuration(250);setAnimation(a);}setImageMatrix(getImageViewMatrix());}// Unchanged from ImageViewTouchBaseprotected float getValue(Matrix matrix, int whichValue) {matrix.getValues(mMatrixValues);return mMatrixValues[whichValue];}// Get the scale factor out of the matrix.protected float getScale(Matrix matrix) {// If the bitmap is set return the scaleif(mBitmap!=null)return getValue(matrix, Matrix.MSCALE_X);// Otherwise return the default value of 1elsereturn 1f;}// Returns the current scale of the view public float getScale() {return getScale(mSuppMatrix);}// Setup the base matrix so that the image is centered and scaled properly.private void setBaseMatrix(Bitmap bitmap, Matrix matrix) {float viewWidth = getWidth();float viewHeight = getHeight();matrix.reset();float widthScale = Math.min(viewWidth / (float)bitmap.getWidth(), 1.0f);float heightScale = Math.min(viewHeight / (float)bitmap.getHeight(), 1.0f);float scale;if (widthScale > heightScale) {scale = heightScale;} else {scale = widthScale;}matrix.setScale(scale, scale);matrix.postTranslate((viewWidth - ((float)bitmap.getWidth() * scale))/2F, (viewHeight - ((float)bitmap.getHeight() * scale))/2F);}// Combine the base matrix and the supp matrix to make the final matrix.protected Matrix getImageViewMatrix() {mDisplayMatrix.set(mBaseMatrix);mDisplayMatrix.postConcat(mSuppMatrix);return mDisplayMatrix;}// Sets the maximum zoom, which is a scale relative to the base matrix. It is calculated to show// the image at 400% zoom regardless of screen or image orientation. If in the future we decode// the full 3 megapixel image, rather than the current 1024x768, this should be changed down to// 200%.protected float maxZoom() {if (mBitmap == null)return 1F;float fw = (float) mBitmap.getWidth() / (float)mThisWidth;float fh = (float) mBitmap.getHeight() / (float)mThisHeight;float max = Math.max(fw, fh) * 16;return max;}// Tries to make best use of the space by zooming the picturepublic float zoomDefault() {if (mBitmap == null)return 1F;float fw = (float)mThisWidth/(float)mBitmap.getWidth();float fh = (float)mThisHeight/(float)mBitmap.getHeight();return Math.max(Math.min(fw, fh),1);}// Unchanged from ImageViewTouchBaseprotected void zoomTo(float scale, float centerX, float centerY) {if (scale > mMaxZoom) {scale = mMaxZoom;}float oldScale = getScale();float deltaScale = scale / oldScale;mSuppMatrix.postScale(deltaScale, deltaScale, centerX, centerY);setImageMatrix(getImageViewMatrix());center(true, true, false);}// Unchanged from ImageViewTouchBaseprotected void zoomTo(final float scale, final float centerX, final float centerY, final float durationMs) {final float incrementPerMs = (scale - getScale()) / durationMs;final float oldScale = getScale();final long startTime = System.currentTimeMillis();// Setup the zoom runnablepost(new Runnable() {public void run() {long now = System.currentTimeMillis();float currentMs = Math.min(durationMs, (float)(now - startTime));float target = oldScale + (incrementPerMs * currentMs);zoomTo(target, centerX, centerY);if (currentMs < durationMs) {post(this);}}});}// Unchanged from ImageViewTouchBasepublic void zoomTo(float scale) {float width = getWidth();float height = getHeight();zoomTo(scale, width/2F, height/2F);}// Unchanged from ImageViewTouchBaseprotected void zoomIn() {zoomIn(sScaleRate);}// Unchanged from ImageViewTouchBaseprotected void zoomOut() {zoomOut(sScaleRate);}// Unchanged from ImageViewTouchBaseprotected void zoomIn(float rate) {if (getScale() >= mMaxZoom) {return; // Don't let the user zoom into the molecular level.}if (mBitmap == null) {return;}float width = getWidth();float height = getHeight();mSuppMatrix.postScale(rate, rate, width/2F, height/2F);setImageMatrix(getImageViewMatrix());}// Unchanged from ImageViewTouchBaseprotected void zoomOut(float rate) {if (mBitmap == null) {return;}float width = getWidth();float height = getHeight();Matrix tmp = new Matrix(mSuppMatrix);tmp.postScale(1F/sScaleRate, 1F/sScaleRate, width/2F, height/2F);if (getScale(tmp) < 1F) {mSuppMatrix.setScale(1F, 1F, width/2F, height/2F);} else {mSuppMatrix.postScale(1F/rate, 1F/rate, width/2F, height/2F);}setImageMatrix(getImageViewMatrix());center(true, true, false);}// Unchanged from ImageViewTouchBaseprotected void postTranslate(float dx, float dy) {mSuppMatrix.postTranslate(dx, dy);}// Fling a view by a distance over timeprotected void scrollBy( float distanceX, float distanceY, final float durationMs ){final float dx = distanceX;final float dy = distanceY;final long startTime = System.currentTimeMillis();mFling = new Runnable() {float old_x= 0;float old_y= 0;public void run(){long now = System.currentTimeMillis();float currentMs = Math.min( durationMs, now - startTime );float x = easeOut( currentMs, 0, dx, durationMs );float y = easeOut( currentMs, 0, dy, durationMs );postTranslate( ( x - old_x ), ( y - old_y ) );center(true, true, false);old_x = x;old_y = y;if ( currentMs < durationMs ) {post( this );}}};post( mFling );}// Gradually slows down a fling velocityprivate float easeOut( float time, float start, float end, float duration){return end * ( ( time = time / duration - 1 ) * time * time + 1 ) + start;}// Custom draw operation to draw the bitmap using mMatrix@Overrideprotected void onDraw(Canvas canvas) {// Check if the bitmap was ever setif(mBitmap!=null && !mBitmap.isRecycled() ){// If the current version is above Gingerbread and the layer type is // hardware accelerated, the paint is no longer neededif( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && getLayerType() == View.LAYER_TYPE_HARDWARE ){canvas.drawBitmap(mBitmap, mMatrix, null);}else{// Check if the time between draws has been met and draw the bitmapif( (System.currentTimeMillis()-mLastDraw) > sPaintDelay ){canvas.drawBitmap(mBitmap, mMatrix, mPaint);mLastDraw = System.currentTimeMillis();}// Otherwise draw the bitmap without the paint and resubmit a new requestelse{canvas.drawBitmap(mBitmap, mMatrix, null);removeCallbacks(mRefresh);postDelayed(mRefresh, sPaintDelay);}}}}// Adjusts the zoom of the viewclass ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {@Overridepublic boolean onScale( ScaleGestureDetector detector ){// Check if the detector is in progress in order to proceedif(detector!=null && detector.isInProgress() ){try{// Grab the scalefloat targetScale = getScale() * detector.getScaleFactor();// Correct for the min scaletargetScale = Math.min( maxZoom(), Math.max( targetScale, 1.0f) );// Zoom and invalidate the viewzoomTo( targetScale, detector.getFocusX(), detector.getFocusY() );invalidate();return true;}catch(IllegalArgumentException e){e.printStackTrace();}}return false;}}// Handles taps and scrolls of the viewprivate class MyGestureListener extendsGestureDetector.SimpleOnGestureListener {@Overridepublic boolean onSingleTapConfirmed(MotionEvent e) {if(mImageTouchedListener!=null){mImageTouchedListener.onImageTouched();return false;}return super.onSingleTapConfirmed(e);}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {// Skip if there are multiple points of contactif ( (e1!=null&&e1.getPointerCount() > 1) || (e2!=null&&e2.getPointerCount() > 1) || (mScaleDetector!=null && mScaleDetector.isInProgress()) ) return false;// Scroll the bitmapif ( getScale() > zoomDefault() ) {removeCallbacks(mFling);postTranslate(-distanceX, -distanceY);center(true, true, false);}// Default casereturn true;}@Overridepublic boolean onDoubleTap(MotionEvent e) {// If the zoom is over 1x, reset to 1xif ( getScale() > zoomDefault() ){zoomTo(zoomDefault());}// If the zoom is default, zoom into 2xelse zoomTo(zoomDefault()*3, e.getX(), e.getY(),200);// Always true as double tap was performedreturn true;}@Overridepublic boolean onFling( MotionEvent e1, MotionEvent e2, float velocityX, float velocityY ){if ( (e1!=null&&e1.getPointerCount() > 1) || (e2!=null&&e2.getPointerCount() > 1) ) return false;if ( mScaleDetector.isInProgress() ) return false;try{float diffX = e2.getX() - e1.getX();float diffY = e2.getY() - e1.getY();if ( Math.abs( velocityX ) > 800 || Math.abs( velocityY ) > 800 ) {scrollBy( diffX / 2, diffY / 2, 300 );invalidate();}}catch(NullPointerException e){}return super.onFling( e1, e2, velocityX, velocityY );}}@Overridepublic boolean onTouchEvent(MotionEvent event) {// If the bitmap was set, check the scale and gesture detectorsif(mBitmap!=null){// Check the scale detectormScaleDetector.onTouchEvent( event );// Check the gesture detectorif(!mScaleDetector.isInProgress())mGestureDetector.onTouchEvent( event );}// Default casereturn true;}}
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="wst.webview" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="wst.webview.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="wst.webview.ShowWebImageActivity" android:configChanges="orientation" android:label="@string/app_name" android:screenOrientation="portrait" android:theme="@style/Transparent" > </activity> </application> <uses-permission android:name="android.permission.INTERNET" /></manifest>
0 0
- android webview 和 js交互
- Android WebView和JS交互
- webview 和android js 交互
- android webview 和 js交互
- Android WebView和JS交互
- android js和webview交互
- Android webView和js交互
- Android Webview和js交互
- webview,js和android交互
- android JS和webview交互
- Android webview使用 webview和js交互
- android webview js交互 第一节 (java和js交互)
- android webview js交互 第一节 (java和js交互)
- android webview js交互 第一节 (java和js交互)
- android webview js交互 第一节 (java和js交互)
- android webview js交互 第一节 (java和js交互) .
- android webview js交互 (java和js交互)
- android webview js交互 第一节 (java和js交互)
- 通过nginx实现内网hadoop、hbase集群对外访问web界面
- EF的连接对象 conventer DbConnection to SqlConnection
- json数据传递
- 关于java字节码框架ASM的学习
- HTTP协议详解
- Android webView和js交互
- Mybatis入门实例(二)——添加ehcache缓存支持
- 求最近的两点坐标
- intent发送邮件
- Android 中Java 和C/C++的相互调用方法
- 通信原理中星座图详解
- Mybatis入门实例(三)——使用MyBatis Generator生成DAO
- Android小知识——dp转成px和px转成dp
- IOS-UIView转UIImage并保存到本地相册