Android疑难杂症-控件任意拖动+点击监听

实现代码(ImageView为例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package com.keqiang.highcloud.ui.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.ImageView;


/**
* Created by KID on 2017/11/14.
* 随意拖动的view
*/
@SuppressLint("AppCompatCustomView")
public class DragView extends ImageView {

private int width;
private int height;
private int screenWidth;
private int screenHeight;
private Context context;

private boolean dragEnable = true;
//是否拖动
private boolean isDrag = false;

public boolean isDrag() {
return isDrag;
}

public boolean isDragEnable() {
return dragEnable;
}

public void setDragEnable(boolean dragEnable) {
this.dragEnable = dragEnable;
}

public DragView(Context context, AttributeSet attrs) {
super(context, attrs);
dragEnable = true;
this.context = context;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getMeasuredWidth();
height = getMeasuredHeight();
}

private float downX;
private float downY;

@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
if (this.isEnabled()) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isDrag = false;
ViewGroup mViewGroup = (ViewGroup) getParent();
if (null != mViewGroup) {
screenWidth = mViewGroup.getWidth();
screenHeight = mViewGroup.getHeight();
}
downX = event.getX();
downY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
Log.e("kid", "ACTION_MOVE");
if (dragEnable) {
final float xDistance = event.getX() - downX;
final float yDistance = event.getY() - downY;
int l, r, t, b;
//当水平或者垂直滑动距离大于10,才算拖动事件
if (Math.abs(xDistance) > 10 || Math.abs(yDistance) > 10) {
Log.e("kid", "Drag");
isDrag = true;
l = (int) (getLeft() + xDistance);
r = l + width;
t = (int) (getTop() + yDistance);
b = t + height;
//不划出边界判断,此处应按照项目实际情况,因为本项目需求移动的位置是手机全屏,
// 所以才能这么写,如果是固定区域,要得到父控件的宽高位置后再做处理
if (l < 0) {
l = 0;
r = l + width;
} else if (r > screenWidth) {
r = screenWidth;
l = r - width;
}
if (t < 0) {
t = 0;
b = t + height;
} else if (b > screenHeight) {
b = screenHeight;
t = b - height;
}

this.layout(l, t, r, b);
}
}
break;
case MotionEvent.ACTION_UP:
setPressed(false);
break;
case MotionEvent.ACTION_CANCEL:
setPressed(false);
break;
}
return true;
}
return false;
}
}

Android常用代码-bugly集成

集成bugly

1
2
//bugly
compile 'com.tencent.bugly:crashreport:latest.release'

添加权限

1
2
3
<!-- bugly start-->
<uses-permission android:name="android.permission.READ_LOGS" />
<!--bugly end-->

Application的onCreate方法中初始化

不带X5内核

1
2
3
4
5
try {
CrashReport.initCrashReport(this, "你的appID", false);
} catch (Exception e) {
e.printStackTrace();
}

带X5内核

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*bugly+x5内核*/
try {
CrashReport.UserStrategy strategy = new CrashReport.UserStrategy(this);
strategy.setCrashHandleCallback(new CrashReport.CrashHandleCallback() {
public Map onCrashHandleStart(int crashType, String errorType, String errorMessage, String errorStack) {
LinkedHashMap map = new LinkedHashMap();
String x5CrashInfo = com.tencent.smtt.sdk.WebView.getCrashExtraMessage(GFApplication.this);
map.put("x5crashInfo", x5CrashInfo);
return map;
}

@Override
public byte[] onCrashHandleStart2GetExtraDatas(int crashType, String errorType, String errorMessage, String errorStack) {
try {
return "Extra data.".getBytes("UTF-8");
} catch (Exception e) {
return null;
}
}
});
CrashReport.initCrashReport(this, "你的appID", false, strategy);
} catch (Exception e) {
e.printStackTrace();
}

Android签名打包-多渠道打包

复制libs

  • common
  • analytics

集成友盟+ App统计功能

在Application的onCreate方法中调用

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 初始化common库
* 参数1:上下文,不能为空
* 参数2:设备类型,UMConfigure.DEVICE_TYPE_PHONE为手机、UMConfigure.DEVICE_TYPE_BOX为盒子,默认为手机
* 参数3:Push推送业务的secret
*/
try {
UMConfigure.init(this, UMConfigure.DEVICE_TYPE_PHONE, "你的appID");
} catch (Exception e) {
e.printStackTrace();
}

添加相应权限

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 必须的权限 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />

<!-- 推荐的权限 -->
<!-- 添加如下权限,以便使用更多的第三方SDK和更精准的统计数据 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

配置渠道

1
2
3
4
5
6
7
8
9
<manifest>
<application ……>
……
<!--umeng start-->
<meta-data android:value="你的AppID" android:name="UMENG_APPKEY"/>
<meta-data android:value="${UMENG_CHANNEL_VALUE}" android:name="UMENG_CHANNEL"/>
<!--umeng end-->
</application>
</manifest>

代码混淆

1
keep class com.umeng.commonsdk.** {*;}

多渠道配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
android {
productFlavors {
wandoujia {}
yingyongbao {}
c360 {}
kq {}
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
}

applicationVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
def fileName
def flavor = productFlavors.name;
if (outputFile != null && outputFile.name.endsWith('.apk')) {
if (variant.buildType.name.equals('release')) {
fileName = "名字_${defaultConfig.versionName}_${flavor}.apk"
} else if (variant.buildType.name.equals('debug')) {
fileName = "名字_${defaultConfig.versionName}_debug_${flavor}.apk"
}
output.outputFile = new File(outputFile.parent, fileName)
}
}
}
}

Android疑难杂症-ViewPager+分组列表+指示器悬停

系统自带方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

<android.support.design.widget.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">

<ImageView
android:id="@+id/main.backdrop"
android:layout_width="wrap_content"
android:layout_height="300dp"
android:scaleType="centerCrop"
android:src="@drawable/material_img"
app:layout_collapseMode="parallax" />

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
app:layout_collapseMode="pin" />

</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>

<android.support.v4.widget.NestedScrollView

android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="50dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/my_txt"
android:textSize="20sp" />

</android.support.v4.widget.NestedScrollView>

</android.support.design.widget.CoordinatorLayout>

此方案不利于屏幕适配,故不采用。

Androidd开源控件-Glide

Glide 4.3.1 (4.x用起来更麻烦了)

集成

1
2
3
4
5
6
7
8
9
repositories {
mavenCentral()
maven { url 'https://maven.google.com' }
}

dependencies {
compile 'com.github.bumptech.glide:glide:4.3.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.3.1'
}

Android常用代码-App更新

APP更新逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
private void checkUpdate() {
String key = SpUtil.getKey();

Api.getApi0()
.CheckUpdate(key, SystemUtil.getPackageInfo(this).versionCode)
.compose(RxHelper.<CheckUpdateResult>io_main())
.subscribe(new Subscriber<CheckUpdateResult>() {
@Override
public void onCompleted() {

}

@Override
public void onError(Throwable e) {

}

@Override
public void onNext(CheckUpdateResult checkUpdateResult) {
if (checkUpdateResult.getCode() == 1) {
CheckUpdateResult.DataEntity data = checkUpdateResult.getData();
showUpdate(data);
}
}
});
}

private void showUpdate(final CheckUpdateResult.DataEntity data) {
if (data != null) {
showTwoBtnDialog("更新", "v" + data.getVersionName() + "\n" + data.getUpdateInfo(), false, new IBaseActivity.OnTwoBtnClick() {
@Override
public void onOk() {
final TextView[] tv = new TextView[1];
final ProgressBar[] pb = new ProgressBar[1];
showUpdateDialog("更新", "即将开始下载...", false, new IBaseActivity.OnOneBtnClickListener() {
@Override
public void onProgress(TextView textView, ProgressBar progressBar) {
tv[0] = textView;
pb[0] = progressBar;
}

@Override
public void onOK() {
}
});
String url = Constants.API + File.separator + data.getUrl();
final String name = "HighNetFix_" + data.getVersionName() + "_" + data.getVersionCode() + ".apk";
OkGo.<File>get(url)
.tag(this)
.execute(new FileCallback(Constants.APK_DOWNLOAD_PATH, name) {
@Override
public void onSuccess(Response<File> response) {
hideUpdateDialog();
ApkUtils.installApk(HomePageActivity.this, BuildConfig.APPLICATION_ID, Constants.APK_DOWNLOAD_PATH, name);
}

@Override
public void onError(Response<File> response) {
hideUpdateDialog();
ToastUtils.showCustomBgToast("下载失败,请检查您的网络设置。");
}

@Override
public void downloadProgress(Progress progress) {
long currentSize = progress.currentSize;
long totalSize = progress.totalSize;
int pro = (int) (currentSize * 100.0 / totalSize + 0.5f);
tv[0].setText("已下载:" + pro + "%");
pb[0].setProgress(pro);
}
});
}

@Override
public void onCancel() {
}
});
}
}