本文共 16945 字,大约阅读时间需要 56 分钟。
禁止当前 Activity截图
<pre>
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE); setContentView(R.layout.activity_main); } </pre>获取当前输入法
<pre>
String currentInputmethod = Settings.Secure.getString(getContentResolver(),Settings.Secure.DEFAULT_INPUT_METHOD);
LogUtil.e("currentInputmethod = "+currentInputmethod); E/LogUtil: [ (MainActivity.java:35)#getInputMethod ] currentInputmethod = com.tencent.qqpinyin/.QQPYInputMethodService </pre>获取手机里面的所有输入法
<pre>
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); // 取得当前所有的输入法 List<InputMethodInfo> infos = imm.getInputMethodList(); for (InputMethodInfo info : infos) { LogUtil.e("输入法包名:" + info.getPackageName()); } ? E/LogUtil: [ (MainActivity.java:32)#getInputMethod ] 输入法包名:com.tencent.qqpinyin ? E/LogUtil: [ (MainActivity.java:32)#getInputMethod ] 输入法包名:com.meizu.flyme.input ? E/LogUtil: [ (MainActivity.java:32)#getInputMethod ] 输入法包名:com.hathy.simplekeyboard ? E/LogUtil: [ (MainActivity.java:32)#getInputMethod ] 输入法包名:com.alex.keyboardview </pre>安卓跟H5交互之基础篇 方式1 - 有漏洞
<pre>
@SuppressLint("JavascriptInterface") @Override public void onCreateData(Bundle bundle) { webView = findView(wv); HtmlHelper.getInstance().webView(webView).javaScriptEnabled(true).applyCacheModeByNetWork(); webView.loadUrl("file:///android_asset/index.html"); webView.addJavascriptInterface(new JSInterface(), "MobileDevice");}
@Override
public void onClick(View v, int id) { super.onClick(v, id); if(R.id.bt_1 == id){ String info = "来自手机内的内容!!!"+new Random().nextInt(100); webView.loadUrl("javascript:paramsFromMobile('"+info+"')"); } }public class JSInterface{
@JavascriptInterface public void callShortToast(String text){ ToastUtil.shortCenter(text); LogUtil.e("dddd"); } } </pre>安卓跟H5交互之基础篇 方式2 - 较安全
<pre>
public class MainActivity extends HJActivity {private WebView webView;@Overridepublic int getLayoutResId() { return R.layout.activity_main;}@SuppressLint("JavascriptInterface")@Overridepublic void onCreateData(Bundle bundle) { webView = findView(wv); WebViewHelper.getInstance(webView).javaScriptEnabled(true).applyCacheModeByNetWork(); webView.loadUrl("file:///android_asset/index.html"); webView.setWebChromeClient(new MySimpleWebChromeClient()); webView.setWebViewClient(new MySimpleWebViewClient());}@Overridepublic void onClick(View v, int id) { super.onClick(v, id); if (R.id.bt_1 == id) { String info = "来自手机内的内容!!!" + new Random().nextInt(100); webView.loadUrl("javascript:paramsFromNative('" + info + "')"); }}private final class MySimpleWebChromeClient extends SimpleWebChromeClient { @Override public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { super.onJsPrompt(view, url, message, defaultValue, result); LogUtil.w("url = " + url + " message = " + message + " defaultValue = " + defaultValue); result.confirm(); return true; }}private final class MySimpleWebViewClient extends SimpleWebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { return false; }}
}
</pre>
view 自动生成随机的 id
<pre>
/** * 作者:Alex * 时间:2016/11/15 18:07 * 简述: */ public class ViewUtil { private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);public static int generateViewId(View view) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { return View.generateViewId(); } for (; ; ) { final int result = sNextGeneratedId.get(); // aapt-generated IDs have the high byte nonzero; clamp to the range under that. int newValue = result + 1; if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. if (sNextGeneratedId.compareAndSet(result, newValue)) { return result; } }}
}
</pre><pre>
public class App extends BaseApp { @Override public void onCreate() { super.onCreate(); onCreateFont(); } private void onCreateFont() { try { Typeface typeface = Typeface.createFromAsset(BaseUtil.app().getAssets(), "font/simkai.ttf"); Field field_3 = Typeface.class.getDeclaredField("SANS_SERIF"); field_3.setAccessible(true); field_3.set(null, typeface); } catch (Exception e) { LogUtil.e(e); } } }<?xml version="1.0" encoding="utf-8"?>
<resources> <style name="alex_theme_no_title" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowActionBar">false</item> <item name="android:windowNoTitle">true</item> <item name="android:typeface">sans</item> </style> </resources> </pre>真正的释放手动绑定点击事件
<pre>
@Override
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(getLayoutResId()); onBindClickListener(); }private void onBindClickListener() {
setOnCickListener(findViewById(android.R.id.content)); }/**
* 设置点击事件 * * @param view View */ private void setOnCickListener(View view) { if (view == null) { LogUtil.w("控件为空"); return; } view.setOnClickListener(this); if (view instanceof ViewGroup) { setOnCickListener((ViewGroup) view); } }/**
* 设置点击事件 * * @param viewGroup ViewGroup */ private void setOnCickListener(ViewGroup viewGroup) { try { viewGroup.setOnClickListener(this); for (int i = 0; i < viewGroup.getChildCount(); i++) { View v = viewGroup.getChildAt(i); if (v instanceof ViewGroup) { setOnCickListener((ViewGroup) v); } else if ((v != null) && (v instanceof View)) { setOnCickListener(v); } } } catch (Exception e) { LogUtil.e(e.toString()); } }</pre>
Intent.FLAGS
<pre>
/**等于清单文件的 singTop, start之后,之前Activity的数据会保留不变 */ intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent);/**等于清单文件的 singTask, start之后,之前Activity的数据会保留不变 */
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); </pre>点击跳转通讯录,选择联系人+手机号码
<pre>
@Override public void onClick(View v) { super.onClick(v); Intent intent = new Intent(Intent.ACTION_PICK,android.provider.ContactsContract.Contacts.CONTENT_URI); //intent.setType("vnd.android.cursor.dir/phone"); startActivityForResult(intent, requestCode4Contact); }@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(data == null){ return; } if(requestCode == requestCode4Contact){ //处理返回的data,获取选择的联系人信息 Uri uri=data.getData(); String[] contacts=ContactUtil.getPhoneContacts(uri,getContentResolver()); etName.setText(contacts[0]); etPhone.setText(contacts[1]); } refreshEditText(etName); refreshEditText(etPhone); }package org.alex.util;
import android.content.ContentResolver; import android.database.Cursor; import android.net.Uri; import android.provider.ContactsContract; public class ContactUtil { /** * [0] 姓名 * [1] 手机号 * */ public static String[] getPhoneContacts(Uri uri, ContentResolver contentResolver){ String[] textArray=new String[2]; String contactId = ""; String name = ""; String phone = ""; if(uri == null){ return textArray; } String url = uri.toString(); String contactSelectId = StringUtil.subString4End(url, "/"); //得到ContentResolver对象 //取得电话本中开始一项的光标 Cursor cursor = contentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); //向下移动光标 while(cursor.moveToNext()) { //取得联系人名字 int nameFieldColumnIndex = cursor.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME); name = cursor.getString(nameFieldColumnIndex); //取得电话号码 contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)); Cursor cursorPhone = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + contactId, null, null); phone = ""; while(cursorPhone.moveToNext()) { phone = cursorPhone.getString(cursorPhone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); LogUtil.e("phone = "+phone); } if(contactSelectId.equals(contactId)){ textArray[0] = name; textArray[1] = trim(phone, ' '); return textArray; } } return textArray; } private static String trim(String text, char oldChar){ if(text == null){ return text; } char[] charArray = text.toCharArray(); StringBuilder builder = new StringBuilder(); for (int i = 0; i < charArray.length; i++) { char indexChar = charArray[i]; if(indexChar !=oldChar){ builder.append(indexChar); } } return builder.toString(); } }</pre>
判断用户是否安装 QQ、微信客户端
<pre>
/** * 判断 用户是否安装微信客户端 */ public static boolean isWeixinAvilible(Context context) { final PackageManager packageManager = context.getPackageManager();// 获取packagemanager List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);// 获取所有已安装程序的包信息 if (pinfo != null) { for (int i = 0; i < pinfo.size(); i++) { String pn = pinfo.get(i).packageName; if (pn.equals("com.tencent.mm")) { return true; } } }return false;} /\*\* \* 判断 用户是否安装QQ客户端 \*/public static boolean isQQClientAvailable(Context context) { final PackageManager packageManager = context.getPackageManager(); Listpinfo = packageManager.getInstalledPackages(0); if (pinfo != null) { for (int i = 0; i < pinfo.size(); i++) { String pn = pinfo.get(i).packageName; LogUtils.e("pn = "+pn); if (pn.equalsIgnoreCase("com.tencent.qqlite") || pn.equalsIgnoreCase("com.tencent.mobileqq")) { return true; } } } return false;}
</pre>
调起 QQ 和 1445607009 发起临时会话
<pre>String url="";
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); </pre>Java 角度、正弦
<pre>
Math.sin((30f /180f) * Math.PI) = 0.5; Math.asin(0.5000) * 180 / Math.PI = 30 ° </pre>一些常用的状态码
100~199:指示信息,表示请求已接收,继续处理
200~299:请求成功,表示请求已被成功接收、理解、接受 300~399:重定向,要完成请求必须进行更进一步的操作 400~499:客户端错误,请求有语法错误或请求无法实现 500~599:服务器端错误,服务器未能实现合法的请求Float 保留2 位小数
<pre>最简单的方法
float a = 123.2334f; float b = (float)(Math.round(a*100))/100; (这里的100就是2位小数点,如果要其它位,如4位,这里两个100改成10000,不足,不补0) </pre><pre>
float apr = Float.parseFloat(JsonUtil.getString(result, "apr")); /*构造方法的字符格式这里如果小数不足2位,会以0补足.*/ DecimalFormat decimalFormat=new DecimalFormat(".00"); String p= decimalFormat.format(apr); LogUtil.e("apr = "+p); </pre>ListView的高度是自适应的,但是Ta有一个最大高度限制
<pre>
public class HeightListView extends ListView {
private Context context;/\*\* listview 最大高度 \*/private int maxHeight;public int getListViewHeight() { return maxHeight;}public void setMaxHeight(int height) { this.maxHeight = (int) dp2Px(height);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (maxHeight > -1) { heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight,MeasureSpec.AT_MOST); } super.onMeasure(widthMeasureSpec, heightMeasureSpec);}public HeightListView(Context context) { super(context); this.context = context;}public HeightListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.context = context;}public HeightListView(Context context, AttributeSet attrs) { super(context, attrs); this.context = context;}/\*\*数据转换: dp---->px\*/private float dp2Px(float dp){ if (context == null) { return -1; } return dp \* context.getResources().getDisplayMetrics().density;}
}
</pre>
监听ScrollView的滑动进度
<pre>
package github.alex.floattitlelayout;
import android.content.Context;
import android.util.AttributeSet; import android.widget.ScrollView;/**
* Created by Alex on 2016/4/3. * 可以被检测是否滑动到顶部的ScrollView */ public class ObservableScrollView extends ScrollView{ private OnScrollListener onScrollListener = null; public ObservableScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public void setOnScrollListener(OnScrollListener onScrollListener) { this.onScrollListener = onScrollListener; }@Overrideprotected void onScrollChanged(int x, int y, int oldx, int oldy) { super.onScrollChanged(x, y, oldx, oldy); if (onScrollListener != null) { onScrollListener.onScroll(this, x, y, oldx, oldy); }}public interface OnScrollListener { public void onScroll(ScrollView scrollView, int x, int y, int oldx, int oldy);}
}
</pre>
屏蔽Edittext复制粘贴、剪切功能
<pre>
package github.alex.helper.inputfilter;
import android.text.InputFilter;
import android.text.Spanned; import android.text.TextUtils; import android.widget.EditText;/**
* no cut paste * 不可以粘贴、剪切的过滤器 * */ public class NcpInputFilter implements InputFilter { private EditText editText; /**屏蔽粘贴功能*/ private boolean isNoPaste; /**解决 剪切 和 粘贴 的 冲突*/ private boolean isAlexPaste; public NccInputFilter(EditText editText) { this.editText = editText; isNoPaste = true; isAlexPaste = false; } /** * @param source 当前键入、键出 的 字符 * @param dest 所有的字符(除当前键入之外) * @param start 新输入的字符串起始下标 * @param end 新输入的字符串终点下标 * @param dstart 原内容发生改变,改变的起点坐标 * @param dend 原内容发生改变,改变的终点坐标 * end > start 表示键入数据;end = 0 = start 表示键出数据 * @return 当前键入 键出的字符 * */ @Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { if(dest == null){ return ""; } if( TextUtils.isEmpty(source) && (dend-dstart > 1)){ /*屏蔽剪切*/ isAlexPaste = true; editText.setText(dest); editText.setSelection(dest.length()); return ""; } if((!TextUtils.isEmpty(source)) && (end-start > 1) && isNoPaste){ if(isAlexPaste){ isAlexPaste = false; return editText.getText(); } /*屏蔽粘贴*/ return ""; } return source; }}
</pre>
由于toolbar默认是居右的,title怎么实现居中么?
由于toolbar有一个16dp的content inset,会如图
用ViewFlipper 写垂直的跑马灯
<pre>
<ViewFlipper
android:id="@+id/vf" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#CCCCCC" android:inAnimation="@anim/bottom_in" android:outAnimation="@anim/bottom_out"></ViewFlipper>
@Override
public void onCreateData(Bundle bundle) { viewFlipper = findView(R.id.vf); viewFlipper.setFlipInterval(1000); viewFlipper.startFlipping(); new Handler() {}.postDelayed(new Runnable() { @Override public void run() { //原生的跑马灯 01 for (int i = 0; i < 3; i++) { View view = LayoutInflater.from(activity).inflate(R.layout.item_flipper, null); TextView textView = findView(view, R.id.tv); setText(textView, "网络的跑马灯 " + i); viewFlipper.addView(view); } }}, 2000);
}
</pre>animateLayoutChanges="true" 你还在自己写动画吗?
android:clipToPadding="false" 你还在根据 position 来控制 间距吗?
android:transcriptMode="normal"
<pre>
默认情况下,当添加的 Item 超出 ListView 的范围后,ListView 并没有刷新让最新一条显示出来。 而在 qq/微信 聊天中,发新的消息后会自动滚动显示出最下面的一条信息。 这个最适合做聊天布局 AbsListView.TRANSCRIPT_MODE_DISABLED // 禁用 AbsListView.TRANSCRIPT_MODE_NORMAL // 正常状态 AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL // 总是滚动到最新一条 </pre>修改输入法中回车按钮的显示内容
<pre>
/** * * IME_ACTION_SEARCH 搜索 * IME_ACTION_SEND 发送 * IME_ACTION_NEXT 下一步 * IME_ACTION_DONE 完成 */ editText.setImeOptions(EditorInfo.IME_ACTION_SEARCH);EditorInfo.IME_ACTION_DONE 可以和其他的标志一起组合使用来设置软键盘,比如:
editText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI|EditorInfo.IME_ACTION_DONE); 注意1:EditorInfo.IME_ACTION_DONE只有对android:singleLine="true"的EditText有效。 注意2:对于EditorInfo.IME_ACTION_DONE,有些输入法并不支持它,比如搜狗拼音输入法。 </pre>监听输入法中的回车按钮
<pre>
/** * 监听输入法按键 * * */ editText.setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) { LogUtil.e("手指弹起, 回车按钮"); return true; }return false;}
});
</pre>
android:duplicateParentState="true"
<pre>
让子View跟随其Parent的状态,如pressed等。 常见的使用场景是某些时候一个按钮很小,我们想要扩大其点击区域的时候通常会再给其包裹一层布局,将点击事件写到Parent上, 这时候如果希望被包裹按钮的点击效果对应的Selector继续生效的话,这时候duplicateParentState就派上用场了。 </pre>android:clipChildren="false" 加在父容器上
tools:text="你是土鳖" 这是预览效果,运行时,看不到
屏蔽多点触碰
<pre>
<LinearLayout xmlns:android="" android:splitMotionEvents="false" /></pre>
假装App 进程包活
<pre>
/*我能做到的,仅仅是让App存活的稍微久一点,仅此而已*/ /*android:alwaysRetainTaskState="true" 只在 入口在 Activity 有效*/ <activity android:name=".ui.MainActivity" android:alwaysRetainTaskState="true" android:theme="@style/alex_theme_cold_start" > <intent-filter> <action android:name="android.intent.action.MAIN"/></activity>
public class MainActivity extends BaseActivity{
@Override public void onBackPressed() { /*写在主页 , 按返回键返回桌面,不结束Activity*/ moveTaskToBack(true); } }</pre>
Android 如何模拟返回键、菜单键、主页键?
<pre>
方法一: Runtime runtime = Runtime.getRuntime(); runtime.exec('input keyevent ' + KeyEvent.KEYCODE_BACK);方法二:
Instrumentation inst = new Instrumentation(); inst.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK); </pre>转载地址:http://dptyo.baihongyu.com/