0.效果
效果图依次为启动界面,第一次显示用户协议对话框,动态获取权限。
系列文章目录导航
1.实现分析
启动基本上没有什么难点,但在真实项目逻辑还是比较多;就是布局,然后显示用户协议对话框,动态处理权限,判断是否显示引导界面,是否显示广告界面等。
2.界面布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".component.splash.activity.SplashActivity">
<!--banner-->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="120dp"
android:src="@drawable/splash_banner" />
<!--logo-->
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/copyright"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp"
android:src="@drawable/splash_logo" />
<!--版权-->
<TextView
android:id="@+id/copyright"
android:textColor="@color/black80"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="30dp"
android:text="@string/copyright" />
</RelativeLayout>
3.是否显示用户协议对话框
if (DefaultPreferenceUtil.getInstance(getHostActivity()).isAcceptTermsServiceAgreement()) {
//已经同意了用户协议
checkPermission();
} else {
showTermsServiceAgreementDialog();
}
4.自定义协议对话框
继承自DialogFragment自定义对话框。
/**
* 服务条款和隐私协议对话框
*/
public class TermServiceDialogFragment extends BaseViewModelDialogFragment<FragmentDialogTermServiceBinding> {
private static final String TAG = "TermServiceDialogFragment";
private View.OnClickListener onAgreementClickListener;
public static TermServiceDialogFragment newInstance() {
Bundle args = new Bundle();
TermServiceDialogFragment fragment = new TermServiceDialogFragment();
fragment.setArguments(args);
return fragment;
}
/**
* 显示对话框
*
* @param fragmentManager
* @param onAgreementClickListener 同意按钮点击回调
*/
public static void show(FragmentManager fragmentManager, View.OnClickListener onAgreementClickListener) {
//创建fragment
TermServiceDialogFragment fragment = newInstance();
fragment.onAgreementClickListener = onAgreementClickListener;
//显示
//TAG只是用来查找Fragment的
//我们这里不需要查找
//所以值可以随便写
fragment.show(fragmentManager, "TermServiceDialogFragment");
}
@Override
protected void initViews() {
super.initViews();
//点击弹窗外边不能关闭
setCancelable(false);
SuperTextUtil.setLinkColor(binding.content, getActivity().getColor(R.color.link));
}
@Override
protected void initDatum() {
super.initDatum();
Spanned content = Html.fromHtml(getString(R.string.term_service_privacy_content));
//lambda写法,监听器里面只有一个方法才能这样写
SpannableStringBuilder result = SuperTextUtil.setHtmlLinkClick(content, data -> Log.d(TAG, "onLinkClick: " + data));
binding.content.setText(result);
}
@Override
protected void initListeners() {
super.initListeners();
binding.primary.setOnClickListener(view -> {
dismiss();
onAgreementClickListener.onClick(view);
});
binding.disagree.setOnClickListener(view -> {
dismiss();
SuperProcessUtil.killApp();
});
}
}
5.动态处理权限
现在做Android必须要动态处理权限,这里使用第三方框架,推荐再用到的时候才动态请求权限,写法和现在一样。
5.1添加动态权限框架
动态处理权限可以直接使用系统API,添加第三方框架目的是使用更加方便。
//动态处理权限
//https://github.com/permissions-dispatcher/PermissionsDispatcher
implementation "com.github.permissions-dispatcher:permissionsdispatcher:4.8.0"
annotationProcessor "com.github.permissions-dispatcher:permissionsdispatcher-processor:4.8.0"
5.2实现
private void checkPermission() {
//让动态框架检查是否授权了
//如果不使用框架就使用系统提供的API检查
//它内部也是使用系统API检查
//只是使用框架就更简单了
SplashActivityPermissionsDispatcher.onPermissionGrantedWithPermissionCheck(this);
}
/**
* 权限授权了就会调用该方法
* 请求相机权限目的是扫描二维码,拍照
*/
@NeedsPermission({
Manifest.permission.CAMERA,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
})
void onPermissionGranted() {
//如果有权限就进入下一步
prepareNext();
}
/**
* 显示权限授权对话框
* 目的是提示用户
*/
@OnShowRationale({
Manifest.permission.CAMERA,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
})
void showRequestPermission(PermissionRequest request) {
new AlertDialog.Builder(getHostActivity())
.setMessage(R.string.permission_hint)
.setPositiveButton(R.string.allow, (dialog, which) -> request.proceed())
.setNegativeButton(R.string.deny, (dialog, which) -> request.cancel()).show();
}
/**
* 拒绝了权限调用
*/
@OnPermissionDenied({
Manifest.permission.CAMERA,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
})
void showDenied() {
//退出应用
finish();
}
/**
* 再次获取权限的提示
*/
@OnNeverAskAgain({
Manifest.permission.CAMERA,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
})
void showNeverAsk() {
//继续请求权限
checkPermission();
}
/**
* 授权后回调
*
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//将授权结果传递到框架
SplashActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
}
6.界面跳转
private void postNext() {
binding.copyright.postDelayed(new Runnable() {
@Override
public void run() {
next();
}
}, Config.SPLASH_DEFAULT_DELAY_TIME);
}
private void next() {
//获取意图的目的是,因为启动该界面的时候,可能携带一些数据
//需要在主界面处理
Intent intent = new Intent();
Intent oldIntent = getIntent();
IntentUtil.cloneIntent(oldIntent, intent);
//if (sp.isLogin()) {
//intent.setClass(getHostActivity(), AdActivity.class);
//} else {
intent.setClass(getHostActivity(), MainActivity.class);
//}
startActivity(intent);
//关闭当前界面
finish();
//禁用启动动画
overridePendingTransition(0, 0);
}
7.总结
到这里启动界面相关逻辑就实现完成了,总体来说还是比较简单的。