QQ提示信息的拖动效果
2015-12-28 17:03
441 查看
这是在GitHub上找到的一个mode,经过我的一下午的调试终于可以用了。
MainActivity:
DraggableFlagView:
ABAppUtil和ABTextUtil只用到其中的四个方法,里面的大部分方法都是没有用的。
ABAppUtil:
ABTextUtil:
attrs文件放到values中:
main:
MainActivity:
package com.example.mylastitemmessage; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Toast; public class MainActivity extends Activity implements DraggableFlagView.OnDraggableFlagViewListener, View.OnClickListener { private DraggableFlagView draggableFlagView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViewById(R.id.main_btn).setOnClickListener(this); draggableFlagView = (DraggableFlagView) findViewById(R.id.main_dfv); draggableFlagView.setOnDraggableFlagViewListener(this); draggableFlagView.setText("7"); } @Override public void onFlagDismiss(DraggableFlagView view) { Toast.makeText(this, "onFlagDismiss", Toast.LENGTH_SHORT).show(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.main_btn: draggableFlagView.setText("7"); break; } } }
DraggableFlagView:
package com.example.mylastitemmessage; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.app.Activity; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Point; import android.text.TextPaint; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.BounceInterpolator; import android.widget.RelativeLayout; import java.util.logging.Logger; /** * Author: wangjie * Email: tiantian.china.2@gmail.com * Github: https://github.com/wangjiegulu/DraggableFlagView * Date: 12/23/14. */ public class DraggableFlagView extends View { private static final String TAG = DraggableFlagView.class.getSimpleName(); public static interface OnDraggableFlagViewListener { /** * 拖拽销毁圆点后的回调 * * @param view */ void onFlagDismiss(DraggableFlagView view); } private OnDraggableFlagViewListener onDraggableFlagViewListener; public void setOnDraggableFlagViewListener(OnDraggableFlagViewListener onDraggableFlagViewListener) { this.onDraggableFlagViewListener = onDraggableFlagViewListener; } public DraggableFlagView(Context context) { super(context); init(context); } private int patientColor = Color.RED; public DraggableFlagView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DraggableFlagView); int indexCount = a.getIndexCount(); for (int i = 0; i < indexCount; i++) { int attrIndex = a.getIndex(i); patientColor = a.getColor(attrIndex, Color.RED); } a.recycle(); init(context); } public DraggableFlagView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } private Context context; private int originRadius; // 初始的圆的半径 private int originWidth; private int originHeight; private int maxMoveLength; // 最大的移动拉长距离 private boolean isArrivedMaxMoved; // 达到了最大的拉长距离(松手可以触发事件) private int curRadius; // 当前点的半径 private int touchedPointRadius; // touch的圆的半径 private Point startPoint = new Point(); private Point endPoint = new Point(); private Paint paint; // 绘制圆形图形 private TextPaint textPaint; // 绘制圆形图形 private Paint.FontMetrics textFontMetrics; private int[] location; private boolean isTouched; // 是否是触摸状态 private Triangle triangle = new Triangle(); private String text = ""; // 正常状态下显示的文字 private void init(Context context) { this.context = context; setBackgroundColor(Color.TRANSPARENT); // 设置绘制flag的paint paint = new Paint(); paint.setColor(patientColor); paint.setAntiAlias(true); // 设置绘制文字的paint textPaint = new TextPaint(); textPaint.setAntiAlias(true); textPaint.setColor(Color.WHITE); textPaint.setTextSize(ABTextUtil.sp2px(context, 12)); textPaint.setTextAlign(Paint.Align.CENTER); textFontMetrics = textPaint.getFontMetrics(); } RelativeLayout.LayoutParams originLp; // 实际的layoutparams RelativeLayout.LayoutParams newLp; // 触摸时候的LayoutParams private boolean isFirst = true; @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // Logger.d(TAG, String.format("onSizeChanged, w: %s, h: %s, oldw: %s, oldh: %s", w, h, oldw, oldh)); if (isFirst && w > 0 && h > 0) { isFirst = false; originWidth = w; originHeight = h; originRadius = Math.min(originWidth, originHeight) / 2; curRadius = originRadius; touchedPointRadius = originRadius; maxMoveLength = ABAppUtil.getDeviceHeight(context) / 6;///// refreshStartPoint(); ViewGroup.LayoutParams lp = this.getLayoutParams(); if (RelativeLayout.LayoutParams.class.isAssignableFrom(lp.getClass())) { originLp = (RelativeLayout.LayoutParams) lp; } newLp = new RelativeLayout.LayoutParams(lp.width, lp.height); } } @Override public void setLayoutParams(ViewGroup.LayoutParams params) { super.setLayoutParams(params); refreshStartPoint(); } /** * 修改layoutParams后,需要重新设置startPoint */ private void refreshStartPoint() { location = new int[2]; this.getLocationInWindow(location); // Logger.d(TAG, "location on screen: " + Arrays.toString(location)); // startPoint.set(location[0], location[1] + h); try { location[1] = location[1] - ABAppUtil.getTopBarHeight((Activity) context);/// } catch (Exception ex) { } startPoint.set(location[0], location[1] + getMeasuredHeight()); // Logger.d(TAG, "startPoint: " + startPoint); } Path path = new Path(); @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.TRANSPARENT); int startCircleX = 0, startCircleY = 0; if (isTouched) { // 触摸状态 startCircleX = startPoint.x + curRadius; startCircleY = startPoint.y - curRadius; // 绘制原来的圆形(触摸移动的时候半径会不断变化) canvas.drawCircle(startCircleX, startCircleY, curRadius, paint); // 绘制手指跟踪的圆形 int endCircleX = endPoint.x; int endCircleY = endPoint.y; canvas.drawCircle(endCircleX, endCircleY, originRadius, paint); if (!isArrivedMaxMoved) { // 没有达到拉伸最大值 path.reset(); double sin = triangle.deltaY / triangle.hypotenuse; double cos = triangle.deltaX / triangle.hypotenuse; // A点 path.moveTo( (float) (startCircleX - curRadius * sin), (float) (startCircleY - curRadius * cos) ); // B点 path.lineTo( (float) (startCircleX + curRadius * sin), (float) (startCircleY + curRadius * cos) ); // C点 path.quadTo( (startCircleX + endCircleX) / 2, (startCircleY + endCircleY) / 2, (float) (endCircleX + originRadius * sin), (float) (endCircleY + originRadius * cos) ); // D点 path.lineTo( (float) (endCircleX - originRadius * sin), (float) (endCircleY - originRadius * cos) ); // A点 path.quadTo( (startCircleX + endCircleX) / 2, (startCircleY + endCircleY) / 2, (float) (startCircleX - curRadius * sin), (float) (startCircleY - curRadius * cos) ); canvas.drawPath(path, paint); } // 绘制文字 float textH = - textFontMetrics.ascent - textFontMetrics.descent; canvas.drawText(text, endCircleX, endCircleY + textH / 2, textPaint); } else { // 非触摸状态 if (curRadius > 0) { startCircleX = curRadius; startCircleY = originHeight - curRadius; canvas.drawCircle(startCircleX, startCircleY, curRadius, paint); if (curRadius == originRadius) { // 只有在恢复正常的情况下才显示文字 // 绘制文字 float textH = - textFontMetrics.ascent - textFontMetrics.descent; canvas.drawText(text, startCircleX, startCircleY + textH / 2, textPaint); } } } // Logger.d(TAG, "circleX: " + startCircleX + ", circleY: " + startCircleY + ", curRadius: " + curRadius); } float downX = Float.MAX_VALUE; float downY = Float.MAX_VALUE; @Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); // Logger.d(TAG, "onTouchEvent: " + event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: isTouched = true; this.setLayoutParams(newLp); endPoint.x = (int) downX; endPoint.y = (int) downY; changeViewHeight(this, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); postInvalidate(); downX = event.getX() + location[0]; downY = event.getY() + location[1]; // Logger.d(TAG, String.format("downX: %f, downY: %f", downX, downY)); break; case MotionEvent.ACTION_MOVE: // 计算直角边和斜边(用于计算绘制两圆之间的填充去) triangle.deltaX = event.getX() - downX; triangle.deltaY = -1 * (event.getY() - downY); // y轴方向相反,所有需要取反 double distance = Math.sqrt(triangle.deltaX * triangle.deltaX + triangle.deltaY * triangle.deltaY); triangle.hypotenuse = distance; // Logger.d(TAG, "triangle: " + triangle); refreshCurRadiusByMoveDistance((int) distance); endPoint.x = (int) event.getX(); endPoint.y = (int) event.getY(); postInvalidate(); break; case MotionEvent.ACTION_UP: isTouched = false; this.setLayoutParams(originLp); if (isArrivedMaxMoved) { // 触发事件 changeViewHeight(this, originWidth, originHeight); postInvalidate(); if (null != onDraggableFlagViewListener) { onDraggableFlagViewListener.onFlagDismiss(this); } // Logger.d(TAG, "触发事件..."); resetAfterDismiss(); } else { // 还原 changeViewHeight(this, originWidth, originHeight); startRollBackAnimation(500/*ms*/); } downX = Float.MAX_VALUE; downY = Float.MAX_VALUE; break; } return true; } /** * 触发事件之后重置 */ private void resetAfterDismiss() { this.setVisibility(GONE); text = ""; isArrivedMaxMoved = false; curRadius = originRadius; postInvalidate(); } /** * 根据移动的距离来刷新原来的圆半径大小 * * @param distance */ private void refreshCurRadiusByMoveDistance(int distance) { if (distance > maxMoveLength) { isArrivedMaxMoved = true; curRadius = 0; } else { isArrivedMaxMoved = false; float calcRadius = (1 - 1f * distance / maxMoveLength) * originRadius; float maxRadius = ABTextUtil.dip2px(context, 2); curRadius = (int) Math.max(calcRadius, maxRadius); // Logger.d(TAG, "[refreshCurRadiusByMoveDistance]curRadius: " + curRadius + ", calcRadius: " + calcRadius + ", maxRadius: " + maxRadius); } } /** * 改变某控件的高度 * * @param view * @param height */ private void changeViewHeight(View view, int width, int height) { ViewGroup.LayoutParams lp = view.getLayoutParams(); if (null == lp) { lp = originLp; } lp.width = width; lp.height = height; view.setLayoutParams(lp); } /** * 回滚状态动画 */ private void startRollBackAnimation(long duration) { ValueAnimator rollBackAnim = ValueAnimator.ofFloat(curRadius, originRadius); rollBackAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float value = (float) animation.getAnimatedValue(); curRadius = (int) value; postInvalidate(); } }); rollBackAnim.setInterpolator(new BounceInterpolator()); // 反弹效果 rollBackAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); DraggableFlagView.this.clearAnimation(); } }); rollBackAnim.setDuration(duration); rollBackAnim.start(); } /** * 计算四个坐标的三角边关系 */ class Triangle { double deltaX; double deltaY; double hypotenuse; @Override public String toString() { return "Triangle{" + "deltaX=" + deltaX + ", deltaY=" + deltaY + ", hypotenuse=" + hypotenuse + '}'; } } public String getText() { return text; } public void setText(String text) { this.text = text; this.setVisibility(VISIBLE); postInvalidate(); } }
ABAppUtil和ABTextUtil只用到其中的四个方法,里面的大部分方法都是没有用的。
ABAppUtil:
package com.example.mylastitemmessage; import android.annotation.TargetApi; import android.app.Activity; import android.app.ActivityManager; import android.app.KeyguardManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.graphics.Rect; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Build; import android.provider.Settings; import android.telephony.TelephonyManager; import android.view.View; import android.view.ViewTreeObserver; import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import java.io.File; import java.lang.reflect.Field; import java.util.List; import java.util.Properties; import java.util.Set; /** * 当前程序是否后台运行 * 当前手机是否处于睡眠 * 当前网络是否已连接 * 当前网络是否wifi状态 * 安装apk * 初始化view的高度 * 初始化view的高度后不可见 * 判断是否为手机 * 获取屏幕宽度 * 获取屏幕高度 * 获取设备的IMEI * 获取设备的mac地址 * 获取当前应用的版本号 * 收集设备信息并以Properties返回 * 收集设备信息并以String返回 * <p> * Created with IntelliJ IDEA. * Author: wangjie email:tiantian.china.2@gmail.com * Date: 13-6-5 * Time: 下午3:14 */ public class ABAppUtil { private static final String TAG = ABAppUtil.class.getSimpleName(); /** * 判断当前应用程序是否后台运行 * 在android5.0以上失效!请使用isApplicationBackground()方法代替! * * @param context * @return */ @TargetApi(Build.VERSION_CODES.CUPCAKE) @Deprecated public static boolean isBackground(Context context) { ActivityManager activityManager = (ActivityManager) context .getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager .getRunningAppProcesses(); for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) { if (appProcess.processName.equals(context.getPackageName())) { if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND) { // Logger.d(TAG, "后台程序: " + appProcess.processName); return true; } else { // Logger.d(TAG, "前台程序: " + appProcess.processName); return false; } } } return false; } /** * 判断当前应用程序处于前台还是后台 * 需要添加权限: <uses-permission android:name="android.permission.GET_TASKS" /> */ public static boolean isApplicationBackground(final Context context) { ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1); if (!tasks.isEmpty()) { ComponentName topActivity = tasks.get(0).topActivity; if (!topActivity.getPackageName().equals(context.getPackageName())) { // Logger.d(TAG, "isBackground: " + true); return true; } } // Logger.d(TAG, "isBackground: " + false); return false; } /** * 判断手机是否处理睡眠 * * @param context * @return */ public static boolean isSleeping(Context context) { KeyguardManager kgMgr = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); boolean isSleeping = kgMgr.inKeyguardRestrictedInputMode(); // Logger.d(TAG, isSleeping ? "手机睡眠中.." : "手机未睡眠..."); return isSleeping; } /** * 检查网络是否已连接 * * @param context * @return * @author com.tiantian */ public static boolean isOnline(Context context) { ConnectivityManager manager = (ConnectivityManager) context .getSystemService(Activity.CONNECTIVITY_SERVICE); NetworkInfo info = manager.getActiveNetworkInfo(); if (info != null && info.isConnected()) { return true; } return false; } /** * 判断当前是否是wifi状态 * * @param context * @return */ public static boolean isWifiConnected(Context context) { ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo wifiNetworkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); if (wifiNetworkInfo.isConnected()) { return true; } return false; } /** * 安装apk * * @param context * @param file */ public static void installApk(Context context, File file) { Intent intent = new Intent(); intent.setAction("android.intent.action.VIEW"); intent.addCategory("android.intent.category.DEFAULT"); intent.setType("application/vnd.android.package-archive"); intent.setData(Uri.fromFile(file)); intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } /** * 初始化View的高宽 * * @param view */ @Deprecated public static void initViewWH(final View view) { view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { view.getViewTreeObserver().removeGlobalOnLayoutListener(this); System.out.println(view + ", width: " + view.getWidth() + "; height: " + view.getHeight()); } }); } /** * 初始化View的高宽并显示不可见 * * @param view */ @Deprecated public static void initViewWHAndGone(final View view) { view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { view.getViewTreeObserver().removeGlobalOnLayoutListener(this); view.setVisibility(View.GONE); } }); } /** * 使用Properties来保存设备的信息和错误堆栈信息 */ private static final String VERSION_NAME = "versionName"; private static final String VERSION_CODE = "versionCode"; private static final String STACK_TRACE = "STACK_TRACE"; /** * 判断是否为手机 * * @param context * @return * @author wangjie */ public static boolean isPhone(Context context) { TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); int type = telephony.getPhoneType(); if (type == TelephonyManager.PHONE_TYPE_NONE) { // Logger.i(TAG, "Current device is Tablet!"); return false; } else { // Logger.i(TAG, "Current device is phone!"); return true; } } /** * 获得设备的屏幕宽度 * * @param context * @return */ public static int getDeviceWidth(Context context) { WindowManager manager = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); return manager.getDefaultDisplay().getWidth(); } /** * 获得设备的屏幕高度 * * @param context * @return */ public static int getDeviceHeight(Context context) { WindowManager manager = (WindowManager) context .getSystemService(Context.WINDOW_SERVICE); return manager.getDefaultDisplay().getHeight(); } /** * 获取设备id(IMEI) * * @param context * @return * @author wangjie */ @TargetApi(Build.VERSION_CODES.CUPCAKE) public static String getDeviceIMEI(Context context) { String deviceId; TelephonyManager telephony = (TelephonyManager) context .getSystemService(Context.TELEPHONY_SERVICE); deviceId = telephony.getDeviceId(); if (deviceId == null) { deviceId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); } // Logger.d(TAG, "当前设备IMEI码: " + deviceId); return deviceId != null ? deviceId : "Unknown"; } /** * 获取设备mac地址 * * @param context * @return * @author wangjie */ // public static String getMacAddress(Context context) { // String macAddress; // WifiManager wifi = (WifiManager) context // .getSystemService(Context.WIFI_SERVICE); // WifiInfo info = wifi.getConnectionInfo(); // macAddress = info.getMacAddress(); // Logger.d(TAG, "当前mac地址: " + (null == macAddress ? "null" : macAddress)); // if (null == macAddress) { // return ""; // } // macAddress = macAddress.replace(":", ""); // return macAddress; // } /** * 获取当前应用程序的版本号 * * @return * @author wangjie */ // public static String getAppVersion() { // String version = "0"; // try { // Context context = ABApplication.getInstance(); // version = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName; // } catch (PackageManager.NameNotFoundException e) { // e.printStackTrace(); // Logger.e(TAG, "getAppVersion", e); // } // Logger.d(TAG, "该应用的版本号: " + version); // return version; // } /** * 收集设备信息 * * @param context */ public static Properties collectDeviceInfo(Context context) { Properties mDeviceCrashInfo = new Properties(); try { // Class for retrieving various kinds of information related to the // application packages that are currently installed on the device. // You can find this class through getPackageManager(). PackageManager pm = context.getPackageManager(); // getPackageInfo(String packageName, int flags) // Retrieve overall information about an application package that is installed on the system. // public static final int GET_ACTIVITIES // Since: API Level 1 PackageInfo flag: return information about activities in the package in activities. PackageInfo pi = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES); if (pi != null) { // public String versionName The version name of this package, // as specified by the <manifest> tag's versionName attribute. mDeviceCrashInfo.put(VERSION_NAME, pi.versionName == null ? "not set" : pi.versionName); // public int versionCode The version number of this package, // as specified by the <manifest> tag's versionCode attribute. mDeviceCrashInfo.put(VERSION_CODE, pi.versionCode); } } catch (PackageManager.NameNotFoundException e) { // Logger.e(TAG, "Error while collect package info", e); } // 使用反射来收集设备信息.在Build类中包含各种设备信息, // 例如: 系统版本号,设备生产商 等帮助调试程序的有用信息 // 返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段 Field[] fields = Build.class.getDeclaredFields(); for (Field field : fields) { try { // setAccessible(boolean flag) // 将此对象的 accessible 标志设置为指示的布尔值。 // 通过设置Accessible属性为true,才能对私有变量进行访问,不然会得到一个IllegalAccessException的异常 field.setAccessible(true); mDeviceCrashInfo.put(field.getName(), field.get(null)); // if (DEBUG) { // Logger.d(TAG, field.getName() + " : " + field.get(null)); // } } catch (Exception e) { // Logger.e(TAG, "Error while collect crash info", e); } } return mDeviceCrashInfo; } /** * 收集设备信息 * * @param context * @return */ public static String collectDeviceInfoStr(Context context) { Properties prop = collectDeviceInfo(context); Set deviceInfos = prop.keySet(); StringBuilder deviceInfoStr = new StringBuilder("{\n"); for (Object item : deviceInfos) { deviceInfoStr.append("\t\t\t").append(item).append(":").append(prop.get(item)).append(", \n"); } deviceInfoStr.append("}"); return deviceInfoStr.toString(); } /** * 是否有SDCard * * @return */ public static boolean haveSDCard() { return android.os.Environment.getExternalStorageState().equals( android.os.Environment.MEDIA_MOUNTED); } /** * 隐藏软键盘 */ @TargetApi(Build.VERSION_CODES.CUPCAKE) public static void hideSoftInput(Context context) { View view = ((Activity) context).getWindow().peekDecorView(); if (view != null) { InputMethodManager inputmanger = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); inputmanger.hideSoftInputFromWindow(view.getWindowToken(), 0); } } /** * 隐藏软键盘 */ @TargetApi(Build.VERSION_CODES.CUPCAKE) public static void hideSoftInput(Context context, EditText edit) { edit.clearFocus(); InputMethodManager inputmanger = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); inputmanger.hideSoftInputFromWindow(edit.getWindowToken(), 0); } /** * 显示软键盘 */ @TargetApi(Build.VERSION_CODES.CUPCAKE) public static void showSoftInput(Context context, EditText edit) { edit.setFocusable(true); edit.setFocusableInTouchMode(true); edit.requestFocus(); InputMethodManager inputManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); inputManager.showSoftInput(edit, 0); } @TargetApi(Build.VERSION_CODES.CUPCAKE) public static void toggleSoftInput(Context context, EditText edit) { edit.setFocusable(true); edit.setFocusableInTouchMode(true); edit.requestFocus(); InputMethodManager inputManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); inputManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); } /** * 回到home,后台运行 * * @param context */ public static void goHome(Context context) { // Logger.d(TAG, "返回键回到HOME,程序后台运行..."); Intent mHomeIntent = new Intent(Intent.ACTION_MAIN); mHomeIntent.addCategory(Intent.CATEGORY_HOME); mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); context.startActivity(mHomeIntent); } /** * 获取状态栏高度 * * @param activity * @return */ @TargetApi(Build.VERSION_CODES.CUPCAKE) public static int getStatusBarHeight(Activity activity) { Rect frame = new Rect(); activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); return frame.top; } /** * 获取状态栏高度+标题栏高度 * * @param activity * @return */ public static int getTopBarHeight(Activity activity) { return activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop(); } /** * 获取网络类型 * * @return */ public static int getNetworkType(Context context) { TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); return telephonyManager.getNetworkType(); } /** * MCC+MNC代码 (SIM卡运营商国家代码和运营商网络代码) * 仅当用户已在网络注册时有效, CDMA 可能会无效 * * @return (中国移动:46000 46002, 中国联通:46001,中国电信:46003) */ public static String getNetworkOperator(Context context) { TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); return telephonyManager.getNetworkOperator(); } /** * 返回移动网络运营商的名字(例:中国联通、中国移动、中国电信) * 仅当用户已在网络注册时有效, CDMA 可能会无效 * * @return */ public static String getNetworkOperatorName(Context context) { TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); return telephonyManager.getNetworkOperatorName(); } /** * 返回移动终端类型 * PHONE_TYPE_NONE :0手机制式未知 * PHONE_TYPE_GSM :1手机制式为GSM,移动和联通 * PHONE_TYPE_CDMA :2手机制式为CDMA,电信 * PHONE_TYPE_SIP:3 * * @return */ public static int getPhoneType(Context context) { TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); return telephonyManager.getPhoneType(); } /** * 在中国,联通的3G为UMTS或HSDPA,移动和联通的2G为GPRS或EGDE,电信的2G为CDMA,电信的3G为EVDO * * @return 2G、3G、4G、未知四种状态 */ // public static int getNetWorkClass(Context context) { // TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); // // switch (telephonyManager.getNetworkType()) { // case TelephonyManager.NETWORK_TYPE_GPRS: // case TelephonyManager.NETWORK_TYPE_EDGE: // case TelephonyManager.NETWORK_TYPE_CDMA: // case TelephonyManager.NETWORK_TYPE_1xRTT: // case TelephonyManager.NETWORK_TYPE_IDEN: // return Constants.NETWORK_CLASS_2_G; // // case TelephonyManager.NETWORK_TYPE_UMTS: // case TelephonyManager.NETWORK_TYPE_EVDO_0: // case TelephonyManager.NETWORK_TYPE_EVDO_A: // case TelephonyManager.NETWORK_TYPE_HSDPA: // case TelephonyManager.NETWORK_TYPE_HSUPA: // case TelephonyManager.NETWORK_TYPE_HSPA: // case TelephonyManager.NETWORK_TYPE_EVDO_B: // case TelephonyManager.NETWORK_TYPE_EHRPD: // case TelephonyManager.NETWORK_TYPE_HSPAP: // return Constants.NETWORK_CLASS_3_G; // // case TelephonyManager.NETWORK_TYPE_LTE: // return Constants.NETWORK_CLASS_4_G; // // default: // return Constants.NETWORK_CLASS_UNKNOWN; // } // } /** * 返回状态:当前的网络链接状态 * 0:其他 * 1:WIFI * 2:2G * 3:3G * 4:4G * * @return 没有网络,2G,3G,4G,WIFI */ // public static int getNetWorkStatus(Context context) { // int netWorkType = Constants.NETWORK_CLASS_UNKNOWN; // // ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); // NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); // // if (networkInfo != null && networkInfo.isConnected()) { // int type = networkInfo.getType(); // // if (type == ConnectivityManager.TYPE_WIFI) { // netWorkType = Constants.NETWORK_WIFI; // } else if (type == ConnectivityManager.TYPE_MOBILE) { // netWorkType = getNetWorkClass(context); // } // } // // return netWorkType; // } /** * Check if this device has a camera */ public static boolean checkCameraHardware(Context context) { return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA); } // public static String getIp(Context context){ // WifiManager wm=(WifiManager)context.getSystemService(Context.WIFI_SERVICE); // //检查Wifi状态 // if(!wm.isWifiEnabled()) // wm.setWifiEnabled(true); // WifiInfo wi=wm.getConnectionInfo(); // //获取32位整型IP地址 // int ipAdd=wi.getIpAddress(); // //把整型地址转换成“*.*.*.*”地址 // return intToIp(ipAdd); // } private static String intToIp(int i) { return (i & 0xFF ) + "." + ((i >> 8 ) & 0xFF) + "." + ((i >> 16 ) & 0xFF) + "." + ( i >> 24 & 0xFF) ; } }
ABTextUtil:
package com.example.mylastitemmessage; import android.content.Context; import android.graphics.drawable.Drawable; import android.text.Spannable; import android.text.SpannableString; import android.text.style.ImageSpan; import android.util.DisplayMetrics; import java.io.*; import java.util.Collection; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; /** * Created with IntelliJ IDEA. * Author: wangjie email:tiantian.china.2@gmail.com * Date: 14-3-28 * Time: 上午10:57 */ public class ABTextUtil { public static final String TAG = ABTextUtil.class.getSimpleName(); /** * 获得字体的缩放密度 * * @param context * @return */ public static float getScaledDensity(Context context) { DisplayMetrics dm = context.getResources().getDisplayMetrics(); return dm.scaledDensity; } /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * 根据手机的分辨率从 px(像素) 的单位 转成为 dp */ public static int px2dip(Context context, float pxValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (pxValue / scale + 0.5f); } /** * 将px值转换为sp值,保证文字大小不变 * * @param pxValue * @return */ public static int px2sp(Context context, float pxValue) { final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; return (int) (pxValue / fontScale + 0.5f); } /** * 将sp值转换为px值,保证文字大小不变 * * @param spValue * @return */ public static int sp2px(Context context, float spValue) { final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; return (int) (spValue * fontScale + 0.5f); } /** * ************************************************************* */ public static boolean isEmpty(Collection collection) { return null == collection || collection.isEmpty(); } public static boolean isEmpty(Map map) { return null == map || map.isEmpty(); } public static boolean isEmpty(Object[] objs) { return null == objs || objs.length <= 0; } public static boolean isEmpty(int[] objs) { return null == objs || objs.length <= 0; } public static boolean isEmpty(CharSequence charSequence) { return null == charSequence || charSequence.length() <= 0; } public static boolean isBlank(CharSequence charSequence) { return null == charSequence || charSequence.toString().trim().length() <= 0; } public static boolean isLeast(Object[] objs, int count) { return null != objs && objs.length >= count; } public static boolean isLeast(int[] objs, int count) { return null != objs && objs.length >= count; } public static boolean isEquals(Object a, Object b) { return (a == null) ? (b == null) : a.equals(b); } public static String trim(CharSequence charSequence) { return null == charSequence ? null : charSequence.toString().trim(); } /** * 摘取里面第一个不为null的字符串 * * @param options * @return */ public static String pickFirstNotNull(CharSequence... options) { if (isEmpty(options)) { return null; } String result = null; for (CharSequence cs : options) { if (null != cs) { result = cs.toString(); break; } } return result; } /** * 摘取里面第一个不为null的字符串 * * @param options * @return */ @SafeVarargs public static <T> T pickFirstNotNull(Class<T> clazz, T... options) { if (isEmpty(options)) { return null; } T result = null; for (T obj : options) { if (null != obj) { result = obj; break; } } return result; } /** * 替换文本为图片 * * @param charSequence * @param regPattern * @param drawable * @return */ public static SpannableString replaceImageSpan(CharSequence charSequence, String regPattern, Drawable drawable) { SpannableString ss = charSequence instanceof SpannableString ? (SpannableString) charSequence : new SpannableString(charSequence); try { ImageSpan is = new ImageSpan(drawable); Pattern pattern = Pattern.compile(regPattern); Matcher matcher = pattern.matcher(ss); while (matcher.find()) { String key = matcher.group(); ss.setSpan(is, matcher.start(), matcher.start() + key.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); } } catch (Exception ex) { // Logger.e(TAG, ex); } return ss; } /** * 压缩字符串到Zip * * @param str * @return 压缩后字符串 * @throws IOException */ public static String compress(String str) throws IOException { if (str == null || str.length() == 0) { return str; } ByteArrayOutputStream out = new ByteArrayOutputStream(); GZIPOutputStream gzip = new GZIPOutputStream(out); gzip.write(str.getBytes()); gzip.close(); return out.toString("ISO-8859-1"); } /** * 解压Zip字符串 * * @param str * @return 解压后字符串 * @throws IOException */ public static String uncompress(String str) throws IOException { if (str == null || str.length() == 0) { return str; } ByteArrayInputStream in = new ByteArrayInputStream(str .getBytes("UTF-8")); return uncompress(in); } /** * 解压Zip字符串 * * @param inputStream * @return 解压后字符串 * @throws IOException */ public static String uncompress(InputStream inputStream) throws IOException { if (inputStream == null) { return null; } ByteArrayOutputStream out = new ByteArrayOutputStream(); GZIPInputStream gunzip = new GZIPInputStream(inputStream); byte[] buffer = new byte[256]; int n; while ((n = gunzip.read(buffer)) >= 0) { out.write(buffer, 0, n); } return out.toString(); } /** * InputStream convert to string * * @param in * @return * @throws IOException */ public static String inputStream2String(InputStream in) throws IOException { StringBuffer out = new StringBuffer(); byte[] b = new byte[4096]; for (int n; (n = in.read(b)) != -1; ) { out.append(new String(b, 0, n)); } return out.toString(); } // /** // * 解压Gzip获取 // * // * @param is // * @return // */ // public static String inputStream2StringFromGZIP(InputStream is) { // StringBuilder resultSb = new StringBuilder(); // BufferedInputStream bis = null; // InputStreamReader reader = null; // try { // bis = new BufferedInputStream(is); // bis.mark(2); // // 取前两个字节 // byte[] header = new byte[2]; // int result = bis.read(header); // // reset输入流到开始位置 // bis.reset(); // // 判断是否是GZIP格式 // int headerData = getShort(header); // // Gzip流的前两个字节是0x1f8b // if (result != -1 && headerData == 0x1f8b) { // is = new GZIPInputStream(bis); // } else { // is = bis; // } // reader = new InputStreamReader(is, "utf-8"); // char[] data = new char[100]; // int readSize; // while ((readSize = reader.read(data)) > 0) { // resultSb.append(data, 0, readSize); // } // } catch (Exception e) { // Logger.e(TAG, e); // } finally { // ABIOUtil.closeIO(is, bis, reader); // } // return resultSb.toString(); // } private static int getShort(byte[] data) { return (int) ((data[0] << 8) | data[1] & 0xFF); } public static String getExceptionStackTrace(Throwable throwable) { if (null == throwable) { return "null"; } StringBuilder sb = new StringBuilder(throwable.getMessage()).append("\n"); StackTraceElement[] elements = throwable.getStackTrace(); for (StackTraceElement element : elements) { sb.append(element.toString()).append("\r\n"); } return sb.toString(); } }
attrs文件放到values中:
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="DraggableFlagView"> <attr name="DraggableFlagView_color" format="color"/> </declare-styleable> </resources>
main:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:dfv="http://schemas.android.com/apk/res-auto" android:layout_width="fill_parent" android:layout_height="fill_parent"> <View android:layout_width="match_parent" android:layout_height="match_parent" android:background="#aabbcc" /> <Button android:id="@+id/main_btn" android:layout_width="match_parent" android:layout_height="48dp" android:layout_alignParentBottom="true" android:background="#cc000000" android:textColor="@android:color/white" android:textSize="20sp" android:text="click me! " > </Button> <com.example.mylastitemmessage.DraggableFlagView android:id="@+id/main_dfv" android:layout_width="20dp" android:layout_height="20dp" android:layout_alignParentBottom="true" android:layout_margin="15dp" dfv:DraggableFlagView_color="#00ff30" /> </RelativeLayout>
相关文章推荐
- Maven多环境配置实战 filter
- c语言程序设计流程图详解
- 使用Maven创建Java项目
- Linux下修改Mysql的用户(root)的密码
- java使用POI进行 Excel文件解析
- 可点击的ImageSpan
- 关于String的两种赋值方式
- 【JavaWeb Structs2学习】 安装配置Structs2
- Spring AOP初级入门-代码篇之XML
- msm8610耳机检测相关
- Boost.Bind用法详解
- 自定义View时,用到Paint Canvas的一些温故,讲讲平时一些效果是怎么画的(基础篇 一)
- 大话设计模式-原型模式
- 自定义View时,用到Paint Canvas的一些温故,讲讲平时一些效果是怎么画的(基础篇 一)
- 【杭电2015年12月校赛H】【模拟 STL-MAP STL-SET stringstream】Study Words 从article中提取中10个没有学过的频率最高单词
- ubuntu 装 jdk 1.7
- socket编程实验-UDP文件传输
- 002.聊聊线程安全
- Linux命令(压缩文件)
- android内存优化总结