Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

LittleSunZ/notes

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

22 Commits

Repository files navigation

notes

开发笔记

1.Android工具下载 http://www.androiddevtools.cn/

2.gradle各个版本下载地址 链接: http://pan.baidu.com/s/1hqjIVlE 密码: 8ccb

3.android studio 打包xml中文提示is not translated in "zh" 解决办法

<resources
 xmlns:tools="http://schemas.android.com/tools"
 tools:ignore="MissingTranslation" >
</resources>

4.android studio 打包混淆提示specified twice. proguard-project.txt 里面-libraryjars jar注释掉 eclipse不要注释

5.如果只有一套图片,最好全都放在drawable-xxhdpi,可以节省图片内存

6.Gson集合使用方法
List peoples = new Gson().fromJson(jsonArray.toString(), new TypeToken<List>() {}.getType());

7.解决百度地图 service 配置 android:process=":remote" 导致application.oncreate创建多次 定位SDK会在单独进程中运行,因此会触发APPLICATION中的oncreat方法,只需要对该进程的名字进行判定就行了。。。。

/**

  • 判断进程名是否是自己的 */
private String getCurProcessName(Context context) {
 int pid = android.os.Process.myPid();
 ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
 for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager.getRunningAppProcesses()) {
 if (appProcess.pid == pid) {
 return appProcess.processName;
 }
 }
 return null;
}

在application的onCreate里面这样判断即可

if ("你的包名".equals(getCurProcessName(this))) {
 SDKInitializer.initialize(this);
}

8.listview设置完数据之后scrollview就自动从顶部跳到中间

scrollview 最上面的一个控件 加这2个属性 
android:focusable="true"
android:focusableInTouchMode="true" 

9.Imageloader框架加载图片及时释放Bitmap

public class ReleaseBitmap implements ImageLoadingListener {
	private List<Bitmap> bitmaps;
	public ReleaseBitmap() {
		// TODO Auto-generated constructor stub
		bitmaps = new ArrayList<Bitmap>();
	}
	@Override
	public void onLoadingCancelled(String arg0, View arg1) {
		// TODO Auto-generated method stub
	}
	@Override
	public void onLoadingComplete(String imageUri, View view, Bitmap bitmap) {
		// TODO Auto-generated method stub
		bitmaps.add(bitmap);
	}
	@Override
	public void onLoadingFailed(String arg0, View arg1, FailReason arg2) {
		// TODO Auto-generated method stub
	}
	@Override
	public void onLoadingStarted(String arg0, View arg1) {
		// TODO Auto-generated method stub
	}
	public void clear() {
		if (bitmaps.size() > 0) {
			for (int i = 0; i < bitmaps.size(); i++) {
				Bitmap b = bitmaps.get(i);
				if (b != null && !b.isRecycled()) {
					b.recycle();
					b = null;
					bitmaps.remove(i);
				}
			}
		}
	}
}

只需要在加载的时候把releaseBitmap类传进去就OK了

ReleaseBitmap releaseBitmap = new ReleaseBitmap();
mImageLoader.displayImage(url, imageview, options, releaseBitmap);

在activity销毁的时候调用releaseBitmap.clear();
adapter也可以写哦,在adapter写一个clear函数

public void clear(){
		releaseBitmap.clear();
}

在activity销毁的时候调用adapter.clear();

10.ViewPager 切换报错 The specified child already has a parent. You must call removeView() on the child's
在adapter里如下面代码这么写即可解决

@Override
public Object instantiateItem(ViewGroup view, int position) {
 if(list.get(position).getParent()==null){
 view.addView(list.get(position));
 }else{
 ((ViewGroup)list.get(position).getParent()).removeView(list.get(position));
 view.addView(list.get(position));
 }
 return list.get(position);
}

11.Fresco图片框架,Facebook出品,必然强大。
Fresco 中设计有一个叫做 image pipeline的模块。它负责从网络,从本地文件系统,本地资源加载图片。为了最大限度节省空间和CPU时间,它含有3级缓存设计(2级内存,1级文件)。
Fresco 中设计有一个叫做 Drawees 模块,方便地显示loading图,当图片不再显示在屏幕上时,及时地释放内存和空间占用。
Fresco 默认配置是在5.0系统以下自动回收不显示图片内存。5.0以上的话需要配置
在application的onCreate初始化配置

ImagePipelineConfig config = ImagePipelineConfig.newBuilder(this)
 .setBitmapMemoryCacheParamsSupplier(new LollipopBitmapMemoryCacheParamsSupplier((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE)))
 .build();
Fresco.initialize(this,config);
public class LollipopBitmapMemoryCacheParamsSupplier implements Supplier {
 private ActivityManager activityManager;
 public LollipopBitmapMemoryCacheParamsSupplier(ActivityManager activityManager) {
 this.activityManager = activityManager;
 }
 @Override
 public MemoryCacheParams get() {
 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
 return new MemoryCacheParams(getMaxCacheSize(), 56, Integer.MAX_VALUE,
 Integer.MAX_VALUE,
 Integer.MAX_VALUE);
 } else {
 return new MemoryCacheParams(
 getMaxCacheSize(),
 256,
 Integer.MAX_VALUE,
 Integer.MAX_VALUE,
 Integer.MAX_VALUE);
 }
 }
 private int getMaxCacheSize() {
 final int maxMemory = Math.min(activityManager.getMemoryClass() * ByteConstants.MB, Integer.MAX_VALUE);
 if (maxMemory < 32 * ByteConstants.MB) {
 return 4 * ByteConstants.MB;
 } else if (maxMemory < 64 * ByteConstants.MB) {
 return 6 * ByteConstants.MB;
 } else {
 if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD) {
 return 8 * ByteConstants.MB;
 } else {
 return maxMemory / 4;
 }
 }
 }
}
//混淆
-dontwarn com.facebook.**

12.github框架排名前100源码 http://www.devstore.cn/essay/essayInfo/5839.html

13.好用的相册选择器 https://github.com/wqandroid/wqgallery

14.轮播banner https://github.com/youth5201314/banner

14.图片压缩利器 https://tinypng.com/

15.微信支付的坑,签名的顺序一定要按照它的来,搞乱一个就不行了,注意金钱单位为分。

public void wxpay(PayInfo payInfos){
	final String appid = WxConfig.WX_APPID;
	final String mch_id = WxConfig.PARTNER;
	final String nonce_str = genNonceStr();
	String body = payInfos.getBody();
	String out_trade_no = payInfos.getOut_trade_no();
	String total_fee = payInfos.getTotal_fee()+"";
	String spbill_create_ip = CommonUtil.getLocalHostIp();
	String notify_url = payInfos.getNotify_url();
	String trade_type = "APP";
	
	
	List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
	packageParams.add(new BasicNameValuePair("appid", appid));
	packageParams.add(new BasicNameValuePair("body", body));
	packageParams.add(new BasicNameValuePair("mch_id", mch_id));
	packageParams.add(new BasicNameValuePair("nonce_str", nonce_str));
	packageParams.add(new BasicNameValuePair("notify_url", notify_url));
	packageParams.add(new BasicNameValuePair("out_trade_no", out_trade_no));
	packageParams.add(new BasicNameValuePair("spbill_create_ip", spbill_create_ip));
	packageParams.add(new BasicNameValuePair("total_fee", total_fee));
	packageParams.add(new BasicNameValuePair("trade_type", trade_type));
	// 生成package 
	StringBuilder sb = new StringBuilder(); 
	 
	for (int i = 0; i < packageParams.size(); i++) { 
	 sb.append(packageParams.get(i).getName()); 
	 sb.append('='); 
	 sb.append(packageParams.get(i).getValue()); 
	 sb.append('&'); 
	} 
	sb.append("key="); 
	sb.append(WxConfig.PARTNER_KEY);
	// 进行md5摘要前,params内容为原始内容,未经过url encode处理 
	String packageSign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase(); 
	packageParams.add(new BasicNameValuePair("sign", packageSign));
	HttpForRequest.wxPay(buildXMLUnifiedOrder(packageParams), new RequestCallBack<String>() {
				
			@Override
			public void onSuccess(ResponseInfo<String> arg0) {
				// TODO Auto-generated method stub
				dismissProgressDialog();
				String return_code = null;
				String return_msg = null;
				String prepay_id = null;
				String sign = null;
				try {
					XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
		 XmlPullParser pull = factory.newPullParser();
		 pull.setInput(new StringReader(arg0.result));
		 int type=pull.getEventType();
		 		while(type!=XmlPullParser.END_DOCUMENT){
		 			String nodeName =pull.getName();
		 			if("return_code".equals(nodeName)){
	 					return_code = pull.nextText();
	 				}
		 			if("return_msg".equals(nodeName)){
		 				return_msg = pull.nextText();
		 			}
		 			if("prepay_id".equals(nodeName)){
		 				prepay_id = pull.nextText();
		 			}
		 			type=pull.next();
		 		}
				} catch (Exception e) {
					// TODO: handle exception
					e.printStackTrace();
				}
				String timeStamp = String.valueOf(genTimeStamp());
				
				if(return_code.equals("SUCCESS")&&return_msg.equals("OK")){
					PayReq req = new PayReq();
					req.appId			= appid;
					req.partnerId		= mch_id;
					req.prepayId		= prepay_id;
					req.nonceStr		= nonce_str;
					req.timeStamp		= timeStamp;
					req.packageValue	= "Sign=WXPay";
					
					List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
					packageParams.add(new BasicNameValuePair("appid", req.appId));
					packageParams.add(new BasicNameValuePair("noncestr", req.nonceStr));
					packageParams.add(new BasicNameValuePair("package", "Sign=WXPay"));
					packageParams.add(new BasicNameValuePair("partnerid", req.partnerId));
					packageParams.add(new BasicNameValuePair("prepayid", req.prepayId));
					packageParams.add(new BasicNameValuePair("timestamp", req.timeStamp));
					// 生成package 
					StringBuilder sb = new StringBuilder(); 
					 
					for (int i = 0; i < packageParams.size(); i++) { 
					 sb.append(packageParams.get(i).getName()); 
					 sb.append('='); 
					 sb.append(packageParams.get(i).getValue()); 
					 sb.append('&'); 
					} 
					sb.append("key="); 
					sb.append(WxConfig.PARTNER_KEY);
					sign = MD5.getMessageDigest(sb.toString().getBytes()).toUpperCase(); ;
					req.sign	= sign;
					// 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信
					api.sendReq(req);
				}else{
					showToast("微信支付失败!");
				}
				
			}
			
			@Override
			public void onFailure(HttpException arg0, String arg1) {
				// TODO Auto-generated method stub
				dismissProgressDialog();
				showToast("微信支付失败!");
			}
	});
}

16.ScrollView中包含Listview的时候,要给Listview重新计算下高度,注意要在setAdapter()之后

/***
 * 给list重新设置高度在scrollview显示
 * 
 * @param listView
 */
public static void setListViewHeightBasedOnChildren(ListView listView) {
	ListAdapter listAdapter = listView.getAdapter();
	if (listAdapter == null) {
		return;
	}
	int totalHeight = 0;
	for (int i = 0; i < listAdapter.getCount(); i++) {
		View listItem = listAdapter.getView(i, null, listView);
		listItem.measure(0, 0);
		totalHeight += listItem.getMeasuredHeight();
	}
	ViewGroup.LayoutParams params = listView.getLayoutParams();
	params.height = totalHeight
			+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));
	listView.setLayoutParams(params);
}

17.当项目中有webView有JS要跟activity交互时,

webView.addJavascriptInterface(new JsInterface(), "aaa");

混淆的时候记得加上,包名.MainActivity是这个类的路径,JsInterface是你的类名

-keepattributes *Annotation*
-keepattributes *JavascriptInterface*
-keepclassmembers class 包名.MainActivity$JsInterface {
 public *;
}

18.Fresco跟百度的SO文件冲突了,启动的时候会报这行的错

SDKInitializer.initialize(this);

解决办法是把所有类型CPU的SO文件都拷贝到libs下,但是有些库没有这么多SO文件的时候,最好的办法是在build.gradle加上

ndk {
 abiFilters "armeabi", "armeabi-v7a", "x86", "mips"
}
android {
 compileSdkVersion 21
 buildToolsVersion "22.0.1"
 defaultConfig {
 applicationId "com.test.app"
 minSdkVersion 10
 targetSdkVersion 21
 multiDexEnabled true
 ndk {
 abiFilters "armeabi", "armeabi-v7a", "x86", "mips"
 }
 }
}

意为系统么有固定只匹配这几个类型的so文件,没有匹配到就找默认的:armeabi或者armeabi-v7a

19.Fresco Gif播放 0.9.0以上需要依赖

compile 'com.facebook.fresco:animated-gif:0.10.0'

20.[Android技术专题]应用开发进阶必经之路之性能优化
https://zhuanlan.zhihu.com/p/22103855

21.【腾讯Bugly干货分享】一步一步实现Android的MVP框架
https://zhuanlan.zhihu.com/p/21771642

22.2016面试宝典
https://www.zhihu.com/question/37483907#answer-43318097

23.滑动ViewPager引起swiperefreshlayout刷新的冲突
ViewPager是Android中提供的页面切换的控件,SwipeRefreshLayout是Android提供的下拉刷新控件,通过SwipeRefreshLayout可以很简单的实现下拉刷新的功能,但是如果SwipeRefreshLayout的子view中如果包含了ViewPager,会发现滑动ViewPager的时候,很容易引起SwipeRefreshLayout的下拉刷新操作为了解决这个冲突可以这样实现

import android.content.Context;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
/**
 * @brief 只在竖直方向才能下拉刷新的控件
 */
public class VerticalSwipeRefreshLayout extends SwipeRefreshLayout {
 private int mTouchSlop;
 // 上一次触摸时的X坐标
 private float mPrevX;
 public VerticalSwipeRefreshLayout(Context context, AttributeSet attrs) {
 super(context, attrs);
 // 触发移动事件的最短距离,如果小于这个距离就不触发移动控件
 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
 }
 @Override
 public boolean onInterceptTouchEvent(MotionEvent event) {
 switch (event.getAction()) {
 case MotionEvent.ACTION_DOWN:
 mPrevX = event.getX();
 break;
 case MotionEvent.ACTION_MOVE:
 final float eventX = event.getX();
 float xDiff = Math.abs(eventX - mPrevX);
 // Log.d("refresh" ,"move----" + eventX + " " + mPrevX + " " + mTouchSlop);
 // 增加60的容差,让下拉刷新在竖直滑动时就可以触发
 if (xDiff > mTouchSlop + 60) {
 return false;
 }
 }
 return super.onInterceptTouchEvent(event);
 }
}

24 WebView内包含https图片地址不显示的情况

mWebview.getSettings().setJavaScriptEnabled(true);//启用js
mWebview.getSettings().setBlockNetworkImage(false);
mWebview.getSettings().setDomStorageEnabled(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
	mWebview.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}

25 android上开源的酷炫的交互动画和视觉效果
http://www.open-open.com/lib/view/open1411443332703.html

26 阴影.9图片制作网站
http://inloop.github.io/shadow4android/

27 pdf工具 https://smallpdf.com/cn/pdf-to-jpg

28 手势缩放view ,xml把需要缩放的view放在ZoomView里面

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
public class ZoomView extends FrameLayout {
 private static final String TAG = "ZoomView";
 public ZoomView(Context context, AttributeSet attrs, int defStyle) {
 super(context, attrs, defStyle);
 }
 public ZoomView(Context context, AttributeSet attrs) {
 super(context, attrs);
 }
 public ZoomView(final Context context) {
 super(context);
 }
 /**
 * Zooming view listener interface.
 */
 public interface ZoomViewListener {
 void onZoomStarted(float zoom, float zoomx, float zoomy);
 void onZooming(float zoom, float zoomx, float zoomy);
 void onZoomEnded(float zoom, float zoomx, float zoomy);
 }
 // zooming
 float zoom = 1.0f;
 float maxZoom = 2.0f;
 float smoothZoom = 1.0f;
 float zoomX, zoomY;
 float smoothZoomX, smoothZoomY;
 private boolean scrolling; // NOPMD by karooolek on 29.06.11 11:45
 // minimap variables
 private boolean showMinimap = false;
 private int miniMapColor = Color.WHITE;
 private int miniMapHeight = -1;
 private String miniMapCaption;
 private float miniMapCaptionSize = 10.0f;
 private int miniMapCaptionColor = Color.WHITE;
 // touching variables
 private long lastTapTime;
 private float touchStartX, touchStartY;
 private float touchLastX, touchLastY;
 private float startd;
 private boolean pinching;
 private float lastd;
 private float lastdx1, lastdy1;
 private float lastdx2, lastdy2;
 // drawing
 private final Matrix m = new Matrix();
 private final Paint p = new Paint();
 // listener
 ZoomViewListener listener;
 private Bitmap ch;
 public float getZoom() {
 return zoom;
 }
 public float getMaxZoom() {
 return maxZoom;
 }
 public void setMaxZoom(final float maxZoom) {
 if (maxZoom < 1.0f) {
 return;
 }
 this.maxZoom = maxZoom;
 }
 public void setMiniMapEnabled(final boolean showMiniMap) {
 this.showMinimap = showMiniMap;
 }
 public boolean isMiniMapEnabled() {
 return showMinimap;
 }
 public void setMiniMapHeight(final int miniMapHeight) {
 if (miniMapHeight < 0) {
 return;
 }
 this.miniMapHeight = miniMapHeight;
 }
 public int getMiniMapHeight() {
 return miniMapHeight;
 }
 public void setMiniMapColor(final int color) {
 miniMapColor = color;
 }
 public int getMiniMapColor() {
 return miniMapColor;
 }
 public String getMiniMapCaption() {
 return miniMapCaption;
 }
 public void setMiniMapCaption(final String miniMapCaption) {
 this.miniMapCaption = miniMapCaption;
 }
 public float getMiniMapCaptionSize() {
 return miniMapCaptionSize;
 }
 public void setMiniMapCaptionSize(final float size) {
 miniMapCaptionSize = size;
 }
 public int getMiniMapCaptionColor() {
 return miniMapCaptionColor;
 }
 public void setMiniMapCaptionColor(final int color) {
 miniMapCaptionColor = color;
 }
 public void zoomTo(final float zoom, final float x, final float y) {
 this.zoom = Math.min(zoom, maxZoom);
 zoomX = x;
 zoomY = y;
 smoothZoomTo(this.zoom, x, y);
 }
 public void smoothZoomTo(final float zoom, final float x, final float y) {
 smoothZoom = clamp(1.0f, zoom, maxZoom);
 smoothZoomX = x;
 smoothZoomY = y;
 if (listener != null) {
 listener.onZoomStarted(smoothZoom, x, y);
 }
 }
 public ZoomViewListener getListener() {
 return listener;
 }
 public void setListner(final ZoomViewListener listener) {
 this.listener = listener;
 }
 public float getZoomFocusX() {
 return zoomX * zoom;
 }
 public float getZoomFocusY() {
 return zoomY * zoom;
 }
 @Override
 public boolean dispatchTouchEvent(final MotionEvent ev) {
// single touch
 if (ev.getPointerCount() == 1) {
 processSingleTouchEvent(ev);
 }
// // double touch
 if (ev.getPointerCount() == 2) {
 processDoubleTouchEvent(ev);
 }
// redraw
 getRootView().invalidate();
 invalidate();
 return true;
 }
 private void processSingleTouchEvent(final MotionEvent ev) {
 final float x = ev.getX();
 final float y = ev.getY();
 final float w = miniMapHeight * (float) getWidth() / getHeight();
 final float h = miniMapHeight;
 final boolean touchingMiniMap = x >= 10.0f && x <= 10.0f + w
 && y >= 10.0f && y <= 10.0f + h;
 if (showMinimap && smoothZoom > 1.0f && touchingMiniMap) {
 processSingleTouchOnMinimap(ev);
 } else {
 processSingleTouchOutsideMinimap(ev);
 }
 }
 private void processSingleTouchOnMinimap(final MotionEvent ev) {
 final float x = ev.getX();
 final float y = ev.getY();
 final float w = miniMapHeight * (float) getWidth() / getHeight();
 final float h = miniMapHeight;
 final float zx = (x - 10.0f) / w * getWidth();
 final float zy = (y - 10.0f) / h * getHeight();
 smoothZoomTo(smoothZoom, zx, zy);
 }
 private void processSingleTouchOutsideMinimap(final MotionEvent ev) {
 final float x = ev.getX();
 final float y = ev.getY();
 float lx = x - touchStartX;
 float ly = y - touchStartY;
 final float l = (float) Math.hypot(lx, ly);
 float dx = x - touchLastX;
 float dy = y - touchLastY;
 touchLastX = x;
 touchLastY = y;
 switch (ev.getAction()) {
 case MotionEvent.ACTION_DOWN:
 touchStartX = x;
 touchStartY = y;
 touchLastX = x;
 touchLastY = y;
 dx = 0;
 dy = 0;
 lx = 0;
 ly = 0;
 scrolling = false;
 break;
 case MotionEvent.ACTION_MOVE:
 if (scrolling || (smoothZoom > 1.0f && l > 30.0f)) {
 if (!scrolling) {
 scrolling = true;
 ev.setAction(MotionEvent.ACTION_CANCEL);
 super.dispatchTouchEvent(ev);
 }
 smoothZoomX -= dx / zoom;
 smoothZoomY -= dy / zoom;
 return;
 }
 break;
 case MotionEvent.ACTION_OUTSIDE:
 case MotionEvent.ACTION_UP:
// tap
 if (l < 30.0f) {
// check double tap
 if (System.currentTimeMillis() - lastTapTime < 500) {
 if (smoothZoom == 1.0f) {
 smoothZoomTo(maxZoom, x, y);
 } else {
 smoothZoomTo(1.0f, getWidth() / 2.0f,
 getHeight() / 2.0f);
 }
 lastTapTime = 0;
 ev.setAction(MotionEvent.ACTION_CANCEL);
 super.dispatchTouchEvent(ev);
 return;
 }
 lastTapTime = System.currentTimeMillis();
 performClick();
 }
 break;
 default:
 break;
 }
 ev.setLocation(zoomX + (x - 0.5f * getWidth()) / zoom, zoomY
 + (y - 0.5f * getHeight()) / zoom);
 ev.getX();
 ev.getY();
 super.dispatchTouchEvent(ev);
 }
 private void processDoubleTouchEvent(final MotionEvent ev) {
 final float x1 = ev.getX(0);
 final float dx1 = x1 - lastdx1;
 lastdx1 = x1;
 final float y1 = ev.getY(0);
 final float dy1 = y1 - lastdy1;
 lastdy1 = y1;
 final float x2 = ev.getX(1);
 final float dx2 = x2 - lastdx2;
 lastdx2 = x2;
 final float y2 = ev.getY(1);
 final float dy2 = y2 - lastdy2;
 lastdy2 = y2;
// pointers distance
 final float d = (float) Math.hypot(x2 - x1, y2 - y1);
 final float dd = d - lastd;
 lastd = d;
 final float ld = Math.abs(d - startd);
 Math.atan2(y2 - y1, x2 - x1);
 switch (ev.getAction()) {
 case MotionEvent.ACTION_DOWN:
 startd = d;
 pinching = false;
 break;
 case MotionEvent.ACTION_MOVE:
 if (pinching || ld > 30.0f) {
 pinching = true;
 final float dxk = 0.5f * (dx1 + dx2);
 final float dyk = 0.5f * (dy1 + dy2);
 smoothZoomTo(Math.max(1.0f, zoom * d / (d - dd)), zoomX - dxk
 / zoom, zoomY - dyk / zoom);
 }
 break;
 case MotionEvent.ACTION_UP:
 default:
 pinching = false;
 break;
 }
 ev.setAction(MotionEvent.ACTION_CANCEL);
 super.dispatchTouchEvent(ev);
 }
 private float clamp(final float min, final float value, final float max) {
 return Math.max(min, Math.min(value, max));
 }
 private float lerp(final float a, final float b, final float k) {
 return a + (b - a) * k;
 }
 private float bias(final float a, final float b, final float k) {
 return Math.abs(b - a) >= k ? a + k * Math.signum(b - a) : b;
 }
 @Override
 protected void dispatchDraw(final Canvas canvas) {
// do zoom
 zoom = lerp(bias(zoom, smoothZoom, 0.05f), smoothZoom, 0.2f);
 smoothZoomX = clamp(0.5f * getWidth() / smoothZoom, smoothZoomX,
 getWidth() - 0.5f * getWidth() / smoothZoom);
 smoothZoomY = clamp(0.5f * getHeight() / smoothZoom, smoothZoomY,
 getHeight() - 0.5f * getHeight() / smoothZoom);
 zoomX = lerp(bias(zoomX, smoothZoomX, 0.1f), smoothZoomX, 0.35f);
 zoomY = lerp(bias(zoomY, smoothZoomY, 0.1f), smoothZoomY, 0.35f);
 if (zoom != smoothZoom && listener != null) {
 listener.onZooming(zoom, zoomX, zoomY);
 }
 final boolean animating = Math.abs(zoom - smoothZoom) > 0.0000001f
 || Math.abs(zoomX - smoothZoomX) > 0.0000001f
 || Math.abs(zoomY - smoothZoomY) > 0.0000001f;
// nothing to draw
 if (getChildCount() == 0) {
 return;
 }
// prepare matrix
 m.setTranslate(0.5f * getWidth(), 0.5f * getHeight());
 m.preScale(zoom, zoom);
 m.preTranslate(
 -clamp(0.5f * getWidth() / zoom, zoomX, getWidth() - 0.5f
 * getWidth() / zoom),
 -clamp(0.5f * getHeight() / zoom, zoomY, getHeight() - 0.5f
 * getHeight() / zoom));
// get view
 final View v = getChildAt(0);
 m.preTranslate(v.getLeft(), v.getTop());
// get drawing cache if available
 if (animating && ch == null && isAnimationCacheEnabled()) {
 v.setDrawingCacheEnabled(true);
 ch = v.getDrawingCache();
 }
// draw using cache while animating
 if (animating && isAnimationCacheEnabled() && ch != null) {
 p.setColor(0xffffffff);
 canvas.drawBitmap(ch, m, p);
 } else { // zoomed or cache unavailable
 ch = null;
 canvas.save();
 canvas.concat(m);
 v.draw(canvas);
 canvas.restore();
 }
// draw minimap
 if (showMinimap) {
 if (miniMapHeight < 0) {
 miniMapHeight = getHeight() / 4;
 }
 canvas.translate(10.0f, 10.0f);
 p.setColor(0x80000000 | 0x00ffffff & miniMapColor);
 final float w = miniMapHeight * (float) getWidth() / getHeight();
 final float h = miniMapHeight;
 canvas.drawRect(0.0f, 0.0f, w, h, p);
 if (miniMapCaption != null && miniMapCaption.length() > 0) {
 p.setTextSize(miniMapCaptionSize);
 p.setColor(miniMapCaptionColor);
 p.setAntiAlias(true);
 canvas.drawText(miniMapCaption, 10.0f,
 10.0f + miniMapCaptionSize, p);
 p.setAntiAlias(false);
 }
 p.setColor(0x80000000 | 0x00ffffff & miniMapColor);
 final float dx = w * zoomX / getWidth();
 final float dy = h * zoomY / getHeight();
 canvas.drawRect(dx - 0.5f * w / zoom, dy - 0.5f * h / zoom, dx
 + 0.5f * w / zoom, dy + 0.5f * h / zoom, p);
 canvas.translate(-10.0f, -10.0f);
 }
// redraw
 getRootView().invalidate();
 invalidate();
 }
}

About

开发笔记

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

AltStyle によって変換されたページ (->オリジナル) /