前语
Android东西类是一些封装好的东西办法的调集,用于简化Android开发中的常见操作和完成特定功用。这些东西类能够协助开发者更高效地编写代码、提高开发效率和减少重复劳动。
一、Intent
1. 获取运用程序信息
(1)从 Intent 或者 URI 中读取运用信息
从 Intent 或者 URI 中读取运用信息APK 包的称号、巨细、图标等信息是比较困难的,因为 Intent 或者 URI 并没有直接提供这些信息。不过,你能够经过以下过程来获取这些信息:
- 运用包名获取运用程序的 ApplicationInfo 目标。
- 运用 PackageManager 目标获取运用程序的称号、巨细、图标等信息。
以下是一种或许的完成办法:
// 从 Intent 中获取 URI
Uri uri = intent.getData();
if (uri == null) {
return;
}
// 从 URI 中获取包名
String packageName = uri.getAuthority();
if (packageName == null) {
return;
}
PackageManager pm = getPackageManager();
ApplicationInfo appInfo;
try {
// 运用包名获取 ApplicationInfo 目标
appInfo = pm.getApplicationInfo(packageName, 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return;
}
// 获取运用称号
String appName = pm.getApplicationLabel(appInfo).toString();
// 获取运用图标
Drawable icon = pm.getApplicationIcon(appInfo);
// 获取运用 APK 文件的途径
String apkPath = appInfo.sourceDir;
// 获取运用 APK 文件的巨细
long apkSize = new File(apkPath).length();
需求留意的是,上述代码仅适用于从 URI 中获取包名的状况。假如你从 Intent 中获取了包名,能够将其替换到代码中的 packageName
变量中。此外,假如 URI 中不包含包名,你需求运用其他办法获取包名,例如解析 URI 中的途径信息。
(2)常规运用 PackageManager
类来获取运用信息
以下是一种示例代码:
PackageManager pm = getPackageManager();
try {
ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0);
// 获取运用称号
String appName = pm.getApplicationLabel(appInfo).toString();
// 获取运用图标
Drawable icon = pm.getApplicationIcon(appInfo);
// 获取运用 APK 文件的途径
String apkPath = appInfo.sourceDir;
// 获取运用 APK 文件的巨细
long apkSize = new File(apkPath).length();
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
在上述代码中,咱们首要创立一个 PackageManager
目标,然后运用 getApplicationInfo(packageName, 0)
办法获取指定包名对应的运用信息。接着,咱们运用 getApplicationLabel(appInfo)
办法获取运用称号,运用 getApplicationIcon(appInfo)
办法获取运用图标。最后,咱们运用 appInfo.sourceDir
获取运用 APK 文件的途径,运用 new File(apkPath).length()
获取运用 APK 文件的巨细。 需求留意的是,假如指定的包名对应的运用不存在,getPackageManager().getApplicationInfo(packageName, 0)
办法会抛出 PackageManager.NameNotFoundException
异常。在代码中,咱们运用 try-catch 块处理该异常。
2、获取Intent携带的uri
(1)获取Uri内容
假如需求兼容其他类型的 Intent,能够在代码中增加相应的处理逻辑。一般来说,能够运用 getData()
办法获取 URI,或者依据 Intent 中的数据类型进行处理。
以下是一种通用的办法,用于兼容多种类型的 Intent:
Uri uri = null;
if (intent != null) {
String action = intent.getAction();
if (Intent.ACTION_VIEW.equals(action)) {
// 获取 VIEW Intent 中的 URI
uri = intent.getData();
} else if (Intent.ACTION_SEND.equals(action)) {
// 获取 SEND Intent 中的 URI
uri = intent.getParcelableExtra(Intent.EXTRA_STREAM);
} else if (Intent.ACTION_SEND_MULTIPLE.equals(action)) {
// 获取 SEND_MULTIPLE Intent 中的 URI
ArrayList<Uri> uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
if (uris != null && !uris.isEmpty()) {
uri = uris.get(0);
}
} else if (Intent.ACTION_CHOOSER.equals(action)) {
// 获取 CHOOSER Intent 中的 URI
Intent chooserIntent = Intent.createChooser(intent, "Select");
if (chooserIntent != null) {
uri = chooserIntent.getParcelableExtra(Intent.EXTRA_STREAM);
}
} else {
// 其他状况,依据数据类型获取 URI
uri = intent.getData();
if (uri == null) {
String type = intent.getType();
if (type != null) {
// 依据数据类型获取 URI
String[] types = type.split("/");
if (types.length == 2) {
String dataType = types[0];
String dataString = intent.getStringExtra(Intent.EXTRA_TEXT);
if (dataString != null) {
uri = Uri.parse(dataString);
}
}
}
}
}
}
在上述代码中,咱们运用 getData()
办法获取 URI,并在其为空的状况下,依据数据类型进行处理。详细地,咱们运用 getType()
办法获取数据类型,然后依据类型进行处理。 在代码中,咱们假设数据类型为 text/plain
,并运用 getStringExtra()
办法获取 EXTRA_TEXT
键对应的字符串。假如字符串不为空,则将其转换为 URI。假如需求兼容其他类型的数据,能够依据实际状况进行扩展。
(3)获取uri数量
在 Intent 中包含多个文件的 URI 的状况下,能够运用 getClipData()
办法获取 ClipData
目标,然后运用 getItemCount()
办法获取 URI 的数量。 以下是一种获取多个文件 URI 数量的办法:
int uriCount = 0;
if (intent != null) {
ClipData clipData = intent.getClipData();
if (clipData != null) {
uriCount = clipData.getItemCount();
} else {
Uri uri = intent.getData();
if (uri != null) {
uriCount = 1;
}
}
}
在上述代码中,咱们首要运用 getClipData()
办法获取 ClipData
目标。假如 ClipData
不为空,则运用 getItemCount()
办法获取 URI 的数量;不然,运用 getData()
办法获取单个 URI,假如 URI 不为空,则数量为 1。 需求留意的是,这种办法只适用于 ACTION_SEND
和 ACTION_SEND_MULTIPLE
类型的 Intent,假如 Intent 的类型不是这两种类型,则无法获取多个文件 URI。
三、ImageView
1、描边圆角作用叠加
能够经过创立一个带有描边的 Shape Drawable,然后将其设置为 ImageView 的布景来完成在 ImageView 中设置黑色描边和圆角的作用。详细过程如下:
(1) 创立一个圆角矩形的 Shape Drawable,并设置其圆角半径。
示例代码如下:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="10dp" />
</shape>
(2)创立一个带有描边的 Shape Drawable,并将圆角矩形的 Shape Drawable 设置为其内部的 Shape Drawable
示例代码如下:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/transparent" />
<stroke android:width="1dp" android:color="#000000" />
<corners android:radius="10dp" />
<padding android:left="1dp" android:top="1dp" android:right="1dp" android:bottom="1dp" />
</shape>
上述代码中,运用 stroke
元从来设置描边的宽度和色彩,运用 padding
元从来设置描边的偏移量,这儿设置为 1dp。同时,运用 solid
元素将布景色彩设置为通明。将圆角矩形的 Shape Drawable 设置为其内部的 Shape Drawable。
(3)在代码中获取 ImageView 目标,并将带有描边的 Shape Drawable 设置为其布景
示例代码如下:
ImageView imageView = findViewById(R.id.imageView);
Drawable drawable = getResources().getDrawable(R.drawable.rounded_corners_with_stroke);
imageView.setBackground(drawable);
上述代码中,经过 getResources().getDrawable()
办法获取带有描边的 Shape Drawable,并将其设置为 ImageView 的布景。 需求留意的是,假如图片的宽度或高度小于圆角半径的两倍,则圆角的作用或许不明显,因而应该依据详细状况适当调整圆角半径。
2、仅在代码中设置图片圆角
能够经过代码完成在 ImageView 中设置圆角。
详细过程如下:
- 创立一个 Bitmap 目标,并将图片资源转换为 Bitmap 目标。示例代码如下:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
- 创立一个圆角矩形的 ShapeDrawable 目标,并设置其圆角半径。示例代码如下:
float radius = 10f; // 圆角半径
ShapeDrawable shapeDrawable = new ShapeDrawable(new RoundRectShape(new float[] {radius, radius, radius, radius, radius, radius, radius, radius}, null, null));
上述代码中,经过 RoundRectShape
的结构函数设置圆角矩形的圆角半径,其间第一个参数是一个 float 数组,指定了圆角的半径,依照左上、右上、右下、左下的顺序排列,假如某个角不需求圆角则将其半径设置为 0;第二个和第三个参数别离指定了外边框和内边框的矩形,这儿不需求设置,因而传入 null。
- 创立一个 BitmapShader 目标,并将其设置为 ShapeDrawable 的 Shader。示例代码如下:
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
shapeDrawable.getPaint().setShader(bitmapShader);
上述代码中,经过 BitmapShader
的结构函数创立一个 BitmapShader 目标,并将其设置为 ShapeDrawable 的 Shader,以完成将 Bitmap 显现到 ShapeDrawable 中。
- 将 ShapeDrawable 设置为 ImageView 的布景。示例代码如下:
imageView.setBackground(shapeDrawable);
上述代码中,经过 setBackground()
办法将 ShapeDrawable 设置为 ImageView 的布景,然后完成在 ImageView 中设置圆角的作用。 完整的代码示例:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image);
float radius = 10f; // 圆角半径
ShapeDrawable shapeDrawable = new ShapeDrawable(new RoundRectShape(new float[] {radius, radius, radius, radius, radius, radius, radius, radius}, null, null));
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
shapeDrawable.getPaint().setShader(bitmapShader);
imageView.setBackground(shapeDrawable);
3、AnimationDrawable点击失效解决
AnimationDrawable
是一个逐帧动画,它能够运用一组 Drawable
目标来创立动画的作用。当运用 AnimationDrawable
在 ImageView
上播映逐帧动画时,假如给 ImageView
设置了点击事情,你或许会发现点击事情不生效。这是因为在播映动画的过程中,ImageView
实际上是被替换成了一个 Drawable
,而不是一个普通的视图。因而,点击事情会被 Drawable
阻拦,而不会传递给 ImageView
。
为了解决这个问题,咱们能够在 ImageView
上增加一个掩盖层,来接收点击事情。详细而言,咱们能够在 ImageView
的父容器上增加一个通明的视图,然后给这个视图设置点击事情。例如:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/my_animation" />
<View
android:id="@+id/click_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent" />
</RelativeLayout>
在这个示例中,咱们在 ImageView
的父容器上增加了一个通明的 View
,并将其掩盖在 ImageView
上。然后,咱们能够给这个 View
设置点击事情,来接收用户的点击操作。 接下来,咱们需求在代码中获取 ImageView
和 View
目标,并别离设置点击事情。例如:
ImageView imageView = findViewById(R.id.image_view);
View clickView = findViewById(R.id.click_view);
clickView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 处理点击事情
}
});
在这个示例中,咱们运用 findViewById()
办法获取 ImageView
和 View
目标,并给 View
设置了点击事情。当用户点击 ImageView
时,点击事情会被 View
阻拦,并传递给 OnClickListener
处理。
需求留意的是,在运用 AnimationDrawable
播映逐帧动画时,也能够经过代码来控制动画的启动、暂停和停止等操作。因而,在实际开发中,或许需求依据详细的业务需求,来动态调整动画的播映状况。
四、Textview
1、文本缩写
(1)在 XML 布局文件中设置
<TextView
android:id="@+id/my_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1" // 设置 TextView 显现的最大行数为 1 行
android:ellipsize="middle" // 设置省掉方位为中间
android:text="这是一个很长的文本,需求省掉显现" />
(2)在 Java 代码中设置
TextView textView = findViewById(R.id.my_text_view);
textView.setSingleLine(true);
textView.setMaxLines(1);
textView.setEllipsize(TextUtils.TruncateAt.MIDDLE);
textView.setText("这是一个很长的文本,需求省掉显现");
五、PopupWindow
1、约束屏幕内显现
PopupWindow 在显现时或许会超出屏幕规模,为了确保 PopupWindow 能够完全显现在屏幕内,能够在 PopupWindow 显现前先计算 PopupWindow 的方位和巨细,然后依据屏幕巨细和 PopupWindow 的方位和巨细,调整 PopupWindow 的方位。 下面是一个判别 PopupWindow 方位是否超出屏幕并调整方位的示例代码:
public void showPopupWindow(View anchorView, View contentView) {
PopupWindow popupWindow = new PopupWindow(contentView,
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
// 计算 PopupWindow 在屏幕中的方位
int[] location = new int[2];
anchorView.getLocationOnScreen(location);
int anchorX = location[0];
int anchorY = location[1];
int anchorWidth = anchorView.getWidth();
int anchorHeight = anchorView.getHeight();
int screenWidth = getResources().getDisplayMetrics().widthPixels;
int screenHeight = getResources().getDisplayMetrics().heightPixels;
// 判别 PopupWindow 是否超出屏幕规模
boolean isOverX = anchorX + popupWindow.getWidth() > screenWidth;
boolean isOverY = anchorY + anchorHeight + popupWindow.getHeight() > screenHeight;
// 假如超出了屏幕规模,调整 PopupWindow 的方位
if (isOverX) {
popupWindow.setWidth(screenWidth - anchorX);
}
if (isOverY) {
popupWindow.setHeight(screenHeight - anchorY - anchorHeight);
}
// 显现 PopupWindow
popupWindow.showAtLocation(anchorView, Gravity.NO_GRAVITY, anchorX, anchorY + anchorHeight);
}
在这个示例代码中,咱们首要创立了一个 PopupWindow,并计算了 PopupWindow 在屏幕中的方位。然后,咱们获取了屏幕的巨细,判别 PopupWindow 是否超出了屏幕规模,并依据状况调整 PopupWindow 的巨细和方位。最后,咱们调用了 PopupWindow 的 showAtLocation 办法,将 PopupWindow 显现在指定方位。
留意,在计算 PopupWindow 的方位和巨细时,或许需求考虑状况栏和导航栏的高度。假如需求考虑状况栏和导航栏的高度,能够运用 ViewCompat.getWindowInsetsController 办法获取 WindowInsetsController,并从中获取状况栏和导航栏的高度。
六、ConstraintLayout
1、布局水平方向均分
要让子 View 在 ConstraintLayout 中水平方向上宽度均分为 50%,能够运用以下办法:
- 在 ConstraintLayout 中增加两个子 View,并且把它们别离放在布局的左边和右侧,例如:
<androidx.constraintlayout.widget.ConstraintLayout
...>
<View
android:id="@+id/view_left"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/view_right"
... />
<View
android:id="@+id/view_right"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="@+id/view_left"
app:layout_constraintEnd_toEndOf="parent"
... />
</androidx.constraintlayout.widget.ConstraintLayout>
2、 然后在两个子 View 上增加水平方向上的权重属性,使它们在水平方向上均分布局的宽度。例如:
<androidx.constraintlayout.widget.ConstraintLayout
...>
<View
android:id="@+id/view_left"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/view_right"
app:layout_constraintHorizontal_weight="1"
... />
<View
android:id="@+id/view_right"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintStart_toEndOf="@+id/view_left"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="1"
... />
</androidx.constraintlayout.widget.ConstraintLayout>
这样,两个子 View 在水平方向上就均分了布局的宽度。假如您想要更改子 View 的宽度份额,只需求调整它们的权重即可。例如,假如您想让左边的子 View 宽度占 30%,右侧的子 View 宽度占 70%,能够将左边的子 View 的权重设置为 3,右侧的子 View 的权重设置为 7。
七、动画
1、同享元素
(1)修改开始方位和巨细
假如您需求运用RectF
目标来获取同享元素的方位和巨细信息,能够运用以下办法
RectF sharedElementRectF = new RectF();
int[] location = new int[2];
sharedElement.getLocationOnScreen(location);
sharedElementRectF.set(location[0], location[1], location[0] + sharedElement.getWidth(), location[1] + sharedElement.getHeight());
在上面的代码中,咱们先经过View.getLocationOnScreen(int[])
办法获取同享元素在屏幕上的坐标,然后运用这些坐标创立一个RectF
目标表明同享元素在屏幕上的方位和巨细信息。 然后,您能够将此RectF
目标传递给ChangeBounds.setEpicenter()
办法作为同享元素过渡的开始方位和巨细。
以下是一个示例代码,展示了如何在setEnterSharedElementCallback()
办法中运用RectF
目标执行同享元素过渡动画:
setEnterSharedElementCallback(new SharedElementCallback() {
@Override
public void onSharedElementStart(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {
super.onSharedElementStart(sharedElementNames, sharedElements, sharedElementSnapshots);
// 获取同享元素的方位和巨细信息
RectF sharedElementRectF = new RectF();
int[] location = new int[2];
sharedElements.get(0).getLocationOnScreen(location);
sharedElementRectF.set(location[0], location[1], location[0] + sharedElements.get(0).getWidth(), location[1] + sharedElements.get(0).getHeight());
// 创立一个同享元素过渡目标,并设置开始方位和巨细
TransitionSet transitionSet = new TransitionSet();
ChangeBounds changeBounds = new ChangeBounds();
changeBounds.setEpicenter(sharedElementRectF);
transitionSet.addTransition(changeBounds);
// 启动同享元素过渡动画
TransitionManager.beginDelayedTransition(container, transitionSet);
}
});
在上面的示例中,咱们运用RectF
目标来创立同享元素过渡的开始方位和巨细,将其传递给ChangeBounds.setEpicenter()
办法,然后启动同享元素过渡动画。