We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
最近忙着开发,对博客的输出暂缓,但是开发中碰到的问题,还需要有个地方随时记录,随时总结经验。主要还是UI层面为主为了下次开发更加顺畅。
安卓项目在建立的时候会默认生成一个themes.xml的主题配置 还有一个themes.xml是在value-night文件夹里面,对应的qualifier为night。
这个配置对应我们手机上的深色模式,有的手机的神色模式是随时间的变化配置的。问题我们项目的设计暂时只设计一套UI,所以深色模式下显示不同的UI显得毕竟奇怪。 最一劳永逸的解决方式
修改themes的parent 把原来的Theme.MaterialComponents.DayNight 改成. NoActionBar Theme.MaterialComponents.Light.NoActionBar
删除 value-night下themes.xml 这里要注意,斩草要除根。除了删除app下的themes.xml,还要检查所有module下的themes,因为安卓资源的打包方式是merge,所以我就出现了只删除app下的night的themes.xml而暗黑模式还存在造成怀疑人生。
学会了BottomSheetDialog的基本用法,但是在xml加了Card的圆角也并不能显示导角,还是四四方方的弹框。 圆角并不能在BottomSheetDialog的内容中设置 需要从AppTheme入手
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="@android:color/white"/> <corners android:topLeftRadius="16dp" android:topRightRadius="16dp"/> </shape>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="bottomSheetDialogTheme">@style/AppBottomSheetDialogTheme</item> </style> <style name="AppBottomSheetDialogTheme" parent="Theme.Design.Light.BottomSheetDialog"> <item name="bottomSheetStyle">@style/AppModalStyle</item> </style> <style name="AppModalStyle" parent="Widget.Design.BottomSheet.Modal"> <item name="android:background">@drawable/rounded_dialog</item> </style>
相关资料
Round corner for BottomSheetDialogFragment
篇幅太大,另外展开
Style&Theme in Android
解决方案简单粗暴 android:padding="0dp" 但是一下子就是找不到找不到!
不知道安卓的UI团队是怎么想的 可以通过android:dropDownWidth来设置宽度,但是没有设置高度的地方,似乎高度就一定和内容项绑定 StackOverflow上的高赞回答是用反射来强行设置,似乎高版本已经不起作用了,暂时就是“无解”
How to limit the height of Spinner drop down view in Android
Spinner控件实在是不熟,目前解决方式就是高度自助话处理。直接override
public static class SimpleArrayAdapter<T> extends ArrayAdapter<T>{ private final List<T> list; private final int tvResource; private int selectedPosition; private final int iconResource; private final int icon; public SimpleArrayAdapter(Context context, @LayoutRes int resource,@IdRes int tvResource,@IdRes int iconResource,@DrawableRes int icon, List<T> objects){ super(context,resource, tvResource ,objects); this.list = objects; this.tvResource = tvResource; this.iconResource = iconResource; this.icon = icon; } public void setSelectedPosition(int selectedPosition) { this.selectedPosition = selectedPosition; } @Override public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { View view = super.getDropDownView(position, convertView, parent); if( tvResource > 0 ) { TextView textView = view.findViewById(tvResource); textView.setTextColor( selectedPosition == position ? Color.BLUE : Color.BLACK ); } return view; } @NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { View view = super.getView(position, convertView, parent); if( iconResource > 0 && icon > 0 ){ ImageView imageView = view.findViewById(iconResource); imageView.setImageResource(icon); } return view; } }
通过getDropDownView的重载来设置文字的背景色
@SuppressLint("ResourceType") @BindingAdapter(value = {"itemsSource","onItemSelected","selectedIndex","resource","tvResource","dropdownResource","iconResource","icon"},requireAll = false) public static <T> void setSpinnerItems(Spinner spinner , List<T> itemsSource, final OnMyItemSelectedListener listener , int index, @LayoutRes int resource, @IdRes int tvResource, @LayoutRes int dropdownResource , @IdRes int iconResource, @DrawableRes int icon){ SimpleArrayAdapter<T> adapter; @SuppressWarnings("unchecked") SimpleArrayAdapter<T> oldAdapter = (SimpleArrayAdapter<T>)spinner.getAdapter(); boolean createNew = oldAdapter != null && oldAdapter.list == itemsSource; if( createNew ){ adapter = oldAdapter; adapter.notifyDataSetChanged(); } else { int viewResource = resource > 0 ? resource : android.R.layout.simple_spinner_item; adapter = new SimpleArrayAdapter<>(spinner.getContext(), viewResource, tvResource, iconResource , icon , itemsSource); adapter.setDropDownViewResource( dropdownResource > 0 ? dropdownResource : android.R.layout.simple_spinner_dropdown_item); if( listener != null ) { spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @SuppressWarnings("OptionalUsedAsFieldOrParameterType") private Optional<Integer> lastPosition = Optional.empty(); @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { //String itemValue = (String) parent.getItemAtPosition(position); if (lastPosition.isPresent() && lastPosition.get() == position) { return; } lastPosition = Optional.of(position); adapter.setSelectedPosition( position ); listener.onItemSelected(position); } @Override public void onNothingSelected(AdapterView<?> parent) { } }); } } spinner.setAdapter(adapter); if( spinner.getSelectedItemPosition() != index ) { spinner.setSelection(index); } }
这是我Spinner 的绑定适配器,配合一起使用的,由于当时觉得不是太复杂,走的思路不是MVVM。现在属性多了有点惨不忍睹。日后一定是要重构的,只是完成现阶段需求。
安卓的界面基础是从官网进去 界面和导航 不过还不能完全符合需求 material控件库基本上算是谷歌的官方库了。 只要依赖声明一下就行很方便 implementation 'com.google.android.material:material:1.4.0' 具体用法参考 material控件库 Android是官方支持,而且api文档用例齐全,是安卓开发的常用网站
implementation 'com.google.android.material:material:1.4.0'
从专用设备到通用移动设备转型的阵痛 以前开发的专用屏,现在开发安卓手机端通用app。第一个变化是没法root了。当然没有啥“变态”功能还能忍。 最大的变化是不能把界面“做死” 不同的手机分辨率是由细微差别的。以前做专用设备,统一的屏幕统一的分辨率。控件布局啥的“焊死”得了,一点问题都没有。现在做手机的应用是老办法就不行了。控件重叠,间距难看等问题都来了。
思路转变 控件不能写死dp,而是适配的方式,比如宽度“顶住”左右控件但是不设置大小,只固定边距,宽度直接和屏幕大小适配 如图constraint-layout支持控件平均分配以及按权重分配 如图6个输入框是按屏幕宽度平均“瓜分”的,先把中间的分割线以及固定边距留下了剩下“平分”
如果这些验证码都要一个一个自己切实在太麻烦了,要怎么让他自然切换那? 好在TextInputEditText有afterTextChanged事件,通过binding库的配合实现
<com.google.android.material.textfield.TextInputEditText android:id="@+id/code_text_input_1" android:layout_width="match_parent" android:layout_height="match_parent" android:afterTextChanged="@{()->dataContext.inputCode( dataContext.code1 , codeTextInput2 )}" android:inputType="number" android:maxLength="1" android:padding="0dp" android:text="@={dataContext.code1}" android:textSize="18sp" /> </com.google.android.material.textfield.TextInputLayout>
public void inputCode( String current , View next ){ //MessageHelper.ShowToast( this.getApplication(), "text changed:" + current ); if(! StringUtils.isTrimEmpty( current ) ){ next.requestFocus(); } }
这样就能实现输入焦点自动切换了。当然还有一些细节并没有做到完美,比如最后一个输入框应该输入后自动隐藏输入法等。慢慢完善吧。
Navigation的单向性的问题 如图fragment->dialog是OK的,dialog->fragment导航图可以画出来,运行给你分分钟报错!!! 冷静一下也合理,fragment和dialog是不平等的,其实我们平时写dialog也是fragment调用的,就是dialog是fragment的下级,下级是无法转为“上级”的。 那fragment怎么拿到dialog的结果 1 viewModel共享 这个前面博客有介绍,但是代价有点大。viewModel的生命周期延长了。一级页面还能接受(本来就是堆栈缓存的),二三级页面就有点不可接受了
2 FragmentResultListener 可以实现
private void closeSelf( String url ){ this.dismiss(); Bundle result = new Bundle(); result.putString("url", url); getParentFragmentManager().setFragmentResult("requestKanbanUrl", result); }
这是dialog的实现 getParentFragmentManager().setFragmentResultListener("requestKanbanUrl", this, (requestKey, bundle) -> { String url = bundle.getString("url"); Logger.i( "receive url: %s",url ); NavDirections action = KanbanFragmentDirections.actionKanbanFragmentToMobileWebFragment(url); this.disposables.add(Single.timer( 100, TimeUnit.MILLISECONDS ) .observeOn(AndroidSchedulers.mainThread()) .subscribe( t-> NavHostFragment.findNavController(this).navigate(action) ) ); }); 这是fragment的FragmentResultListener, 通过delay来进行跳转 因为FragmentResult获取在前,dialog关闭在后,跳转必须要在dialog关闭以后,所以不得不加了一把延时,确实有一点点奇葩。所以以后这种情况要考虑dialog是否要踢出导航了
当“翻墙”也不能挽救gradle下载的时候,就只能靠镜像了
repositories { maven { url 'https://maven.aliyun.com/repository/central' } maven { url 'https://maven.aliyun.com/repository/google' } google() mavenCentral() }
在project级别上的build.gradle加上两行maven。 速度飞快,很好
相关参考站点
先罗列再填坑
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
最近忙着开发,对博客的输出暂缓,但是开发中碰到的问题,还需要有个地方随时记录,随时总结经验。主要还是UI层面为主为了下次开发更加顺畅。
暗黑模式问题
安卓项目在建立的时候会默认生成一个themes.xml的主题配置
还有一个themes.xml是在value-night文件夹里面,对应的qualifier为night。
这个配置对应我们手机上的深色模式,有的手机的神色模式是随时间的变化配置的。问题我们项目的设计暂时只设计一套UI,所以深色模式下显示不同的UI显得毕竟奇怪。
最一劳永逸的解决方式
修改themes的parent
把原来的Theme.MaterialComponents.DayNight 改成. NoActionBar Theme.MaterialComponents.Light.NoActionBar
删除 value-night下themes.xml
这里要注意,斩草要除根。除了删除app下的themes.xml,还要检查所有module下的themes,因为安卓资源的打包方式是merge,所以我就出现了只删除app下的night的themes.xml而暗黑模式还存在造成怀疑人生。
BottomSheetDialog增加圆形导角问题
学会了BottomSheetDialog的基本用法,但是在xml加了Card的圆角也并不能显示导角,还是四四方方的弹框。
圆角并不能在BottomSheetDialog的内容中设置
需要从AppTheme入手
相关资料
Round corner for BottomSheetDialogFragment
theme 设置问题
篇幅太大,另外展开
Style&Theme in Android
Spinner的文字和下拉图标间距问题
解决方案简单粗暴 android:padding="0dp"
但是一下子就是找不到找不到!
Spinner的高度设置问题
不知道安卓的UI团队是怎么想的
可以通过android:dropDownWidth来设置宽度,但是没有设置高度的地方,似乎高度就一定和内容项绑定
StackOverflow上的高赞回答是用反射来强行设置,似乎高版本已经不起作用了,暂时就是“无解”
How to limit the height of Spinner drop down view in Android
Spinner选中项文字高亮显示问题
Spinner控件实在是不熟,目前解决方式就是高度自助话处理。直接override
通过getDropDownView的重载来设置文字的背景色
这是我Spinner 的绑定适配器,配合一起使用的,由于当时觉得不是太复杂,走的思路不是MVVM。现在属性多了有点惨不忍睹。日后一定是要重构的,只是完成现阶段需求。
Material Design控件应用简介
安卓的界面基础是从官网进去 界面和导航
不过还不能完全符合需求
material控件库基本上算是谷歌的官方库了。
只要依赖声明一下就行很方便
implementation 'com.google.android.material:material:1.4.0'
具体用法参考
material控件库
Android是官方支持,而且api文档用例齐全,是安卓开发的常用网站
适配多种手机分辨率的弹性布局方案
从专用设备到通用移动设备转型的阵痛
以前开发的专用屏,现在开发安卓手机端通用app。第一个变化是没法root了。当然没有啥“变态”功能还能忍。
最大的变化是不能把界面“做死”
不同的手机分辨率是由细微差别的。以前做专用设备,统一的屏幕统一的分辨率。控件布局啥的“焊死”得了,一点问题都没有。现在做手机的应用是老办法就不行了。控件重叠,间距难看等问题都来了。
思路转变
控件不能写死dp,而是适配的方式,比如宽度“顶住”左右控件但是不设置大小,只固定边距,宽度直接和屏幕大小适配
如图constraint-layout支持控件平均分配以及按权重分配
如图6个输入框是按屏幕宽度平均“瓜分”的,先把中间的分割线以及固定边距留下了剩下“平分”
“随心”的控制文本框的焦点
如果这些验证码都要一个一个自己切实在太麻烦了,要怎么让他自然切换那?
好在TextInputEditText有afterTextChanged事件,通过binding库的配合实现
这样就能实现输入焦点自动切换了。当然还有一些细节并没有做到完美,比如最后一个输入框应该输入后自动隐藏输入法等。慢慢完善吧。
Navigation中模态Fragment和普通Fragment的通信问题
Navigation的单向性的问题
如图fragment->dialog是OK的,dialog->fragment导航图可以画出来,运行给你分分钟报错!!!
冷静一下也合理,fragment和dialog是不平等的,其实我们平时写dialog也是fragment调用的,就是dialog是fragment的下级,下级是无法转为“上级”的。
那fragment怎么拿到dialog的结果
1 viewModel共享
这个前面博客有介绍,但是代价有点大。viewModel的生命周期延长了。一级页面还能接受(本来就是堆栈缓存的),二三级页面就有点不可接受了
2 FragmentResultListener
可以实现
这是dialog的实现
getParentFragmentManager().setFragmentResultListener("requestKanbanUrl", this, (requestKey, bundle) -> {
String url = bundle.getString("url");
Logger.i( "receive url: %s",url );
NavDirections action = KanbanFragmentDirections.actionKanbanFragmentToMobileWebFragment(url);
this.disposables.add(Single.timer( 100, TimeUnit.MILLISECONDS )
.observeOn(AndroidSchedulers.mainThread())
.subscribe( t-> NavHostFragment.findNavController(this).navigate(action) ) );
});
这是fragment的FragmentResultListener,
通过delay来进行跳转
因为FragmentResult获取在前,dialog关闭在后,跳转必须要在dialog关闭以后,所以不得不加了一把延时,确实有一点点奇葩。所以以后这种情况要考虑dialog是否要踢出导航了
gradle加速问题解决
当“翻墙”也不能挽救gradle下载的时候,就只能靠镜像了
在project级别上的build.gradle加上两行maven。
速度飞快,很好
相关参考站点
先罗列再填坑
The text was updated successfully, but these errors were encountered: