(2)比如vivo 折叠屏高端手机,提供更优质的视觉体验,属于折叠屏机型。
(3)比如vivo pad,拥有优秀的操作手感和高级的质感,属于平板机型。
可是随着这种形形色色机型的出现,那么问题就来了:
案例2:某新闻资讯类APP,在pad上的适配效果如下,可见的范围内,信息流展示内容较少,图片有拉伸、模糊的问题。
然后才是需要解决的问题:




通过在AndroidManifest.xml中设置:android:screenOrientation属性a) android:screenOrientation="portrait" 强制竖屏;b) android:screenOrientation="landscape" 强制横屏;c) android:screenOrientation="unspecified" 默认值,可以横竖屏切换;方式2)在代码中设置:
activity.setRequestedOrientation(****);a) setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 设置竖屏;b)setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 设置横屏;c)setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 可以横竖屏切换;(3)不同设备支持不同的屏幕横竖屏方式1)直板屏:因为是强制竖屏,所以,可以通过在AndroidManifest.xml中给Activity设置android:screenOrientation="portrait"。2)折叠屏:外屏与直板屏是保持一致的,暂且不讨论。但是内屏(大屏)要支持横竖屏切换。如果是一套代码,显然是无法通过AndroidManifest文件来实现的。这里其实系统框架已经帮我们实现了对应内屏时横竖屏的逻辑。总结就是,折叠屏可以与直板屏保持一致,在AndroidManifest.xml中给Activity设置android:screenOrientation="portrait",如果切换到内屏时,系统自动忽略掉screenOrientation属性值,强行支持横竖屏切换。3)PAD端:当然了,并不是所有的项目对应的系统都会自动帮我们忽略screenOrientation属性值,这时候就需要我们自己来实现了。我们通过在Activity的基类中设置setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED),发现确实能够使当前页面横竖屏自由切换了。但是在启动activity的时候遇到了问题。当我们从横屏状态A界面启动一个acitivity的B界面时,发现B界面先是竖屏,然后切换到了横屏(如图1所示)。再试了多次依旧如此,肉眼可见的切换过程显然不能满足我们的需求。这说明通过java代码动态调整横竖屏的技术方向是行不通的。综上所述,通过同一份代码无法满足PAD端和直板屏的互斥的需求。
那还有没有其他方式呢。别忘了,我们Android打包全流程是通过gradle完成的,我们是不是可以通过切面编程的思维,针对不同的设备打出不同的包。方案确定了,在此进行技术验证。gradle编译其中一个重要环节就是对依赖的aar、本地module中的AndroidManifest文件进行merge,最终输出一份临时的完整清单文件,存放在*/app/build/intermediates/merged_manifest/**Release/路径下。因此,我们可以在AndroidManifest文件merge完成之后对该临时文件中的android:screenOrientation字段值信息进行动态修改,修改完成之后再存回去。这样针对pad端就可以单独打出一份apk文件。核心代码如下://pad支持横竖屏
def processManifestTask = project.tasks.getByName("processDefaultNewSignPadReleaseManifest");
if (processManifestTask != null) {
processManifestTask.doLast { pmt ->
def manifestPath = pmt.getMultiApkManifestOutputDirectory().get().toString() + "/AndroidManifest.xml"
if (new File(manifestPath).exists()) {
String manifest = file(manifestPath).getText()
manifest = manifest.replaceAll("android:screenOrientation=\"portrait\"", "android:screenOrientation=\"unspecified\"");
file(manifestPath).write(manifest)
println(" =============================================================== manifestPath: " + manifestPath)
}
}
}

2、高度不变,裁剪物料对于模块3的图片,可以回顾3.2中的展示样式,要求是



如上图所示,选购页可以大致分为 分类导航栏区域 和 内容区域,其中内容区域是由多个楼层组成。
如图所示,能够直观地感受到,从直板手机到折叠屏内屏再到Pad横屏,当设备的可显示面积增大时,页面充分利用空间展示更多的商品信息。/**
* @function 判断当前手机的屏幕是处于哪个屏幕类型:目前三个屏幕范围:分别为 <= 528dp、528 ~ 696dp、> 696dp,对应的分别是正常直板手机、折叠屏手机内屏和Pad竖屏、和Pad横屏
*/
public class ScreenTypeUtil {
public static final int NORMAL_SCREEN_MAX_WIDTH_RESOLUTION = 1584; // 正常直板手机:屏幕最大宽度分辨率;Pad的分辨率(1600*2560), 1584 = 528 * 3, 528dp是UI在精选页标注的直板手机范围
public static final int MIDDLE_SCREEN_MAX_WIDTH_RESOLUTION = 2088; // 折叠屏手机:屏幕最大宽度分辨率(1916*1964, 旋转:1808*2072),2088 = 696 * 3, 2088dp是UI在精选页标注的折叠屏展开范围
public static final int LARGE_SCREEN_MAX_WIDTH_RESOLUTION = 2560; // 大屏幕设备:屏幕宽度暂定为 Pad的高度
public static final int NORMAL_SCREEN = 0; // 正常直版手机屏幕
public static final int MIDDLE_SCREEN = 1; // 折叠屏手机内屏展开、Pad竖屏
public static final int LARGE_SCREEN = 2; // Pad横屏
public static int getScreenType() {
Configuration configuration = BaseApplication.getApplication().getResources().getConfiguration();
return getScreenType(configuration);
}
// 注意这里的newConfig 在Activity、Fragment、View 中的onConfigurationChanged中获得的newConfig传入,如果获得不了该值,可以使用getScreenType()方法
public static int getScreenType(@NonNull Configuration newConfig) {
// Pad 通过机型标志位及当前处于横竖屏状态 来判断当前屏幕类型
if (SystemInfoUtils.isPadDevice()) {
return newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE ? LARGE_SCREEN : MIDDLE_SCREEN;
}
// Fold折叠屏 通过机型标志及内外屏状态 来判断当前屏幕类型
if (SystemInfoUtils.isFoldableDevice()) {
return SystemInfoUtils.isInnerScreen(newConfig) ? MIDDLE_SCREEN : NORMAL_SCREEN;
}
// 普通手机 通过分辨率判断
return AppInfoUtils.getScreenWidth() <= NORMAL_SCREEN_MAX_WIDTH_RESOLUTION ? NORMAL_SCREEN : (AppInfoUtils.getScreenWidth() <= MIDDLE_SCREEN_MAX_WIDTH_RESOLUTION ? MIDDLE_SCREEN : LARGE_SCREEN);
}
}<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root_classify_horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<xxx.widget.HeaderAndFooterRecyclerView
android:id="@+id/shop_product_multi_rv"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>//这里的normalProductMultiClassifyUiBeanList集合中存放了2个商品信息
for (ProductMultiClassifyUiBean productMultiClassifyUiBean : normalProductMultiClassifyUiBeanList) {
productMultiClassifyUiBean.setFirstFloor(isFirstFloor);
shopListDataWrapper.addNormalBaseUiBeans(productMultiClassifyUiBean);
}
//这里的normalProductMultiClassifyUiBeanList集合中存放了3个商品信息
for (ProductMultiClassifyUiBean productMultiClassifyUiBean : widthProductMultiClassifyUiBeanList) {
productMultiClassifyUiBean.setFirstFloor(isFirstFloor);
shopListDataWrapper.addWidthBaseUiBeans(productMultiClassifyUiBean);
}public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
//1、 首先进行内容区域中的RecyclerViewAdapter、数据源判空
if (mRecyclerViewAdapter == null || mPageBeanAll == null) {
return;
}
//2、判断当前的屏幕类型,注意:这个地方是调用3提供的方法:ScreenTypeUtil.getScreenType(newConfig)
// 直板手机、折叠屏外屏
if (ScreenTypeUtil.NORMAL_SCREEN == ScreenTypeUtil.getScreenType(newConfig)) {
mPageBeanAll.setBaseUiBeans(mPageBeanAll.getNormalBaseUiBeans());
} else if (ScreenTypeUtil.MIDDLE_SCREEN == ScreenTypeUtil.getScreenType(newConfig)) {
if (SystemInfoUtils.isPadDevice()) {
// Pad的竖屏
mPageBeanAll.setBaseUiBeans(mPageBeanAll.getNormalBaseUiBeans());
} else {
// 折叠屏的内屏
mPageBeanAll.setBaseUiBeans(mPageBeanAll.getWidthBaseUiBeans());
}
} else {
// Pad的横屏、大分辨率屏幕
mPageBeanAll.setBaseUiBeans(mPageBeanAll.getWidthBaseUiBeans());
}
//获取当前屏幕类型的最新数据源
mRecyclerViewAdapter.setDataSource(mPageBeanAll.getBaseUiBeans());
//数据源驱动楼层UI改变
mRecyclerViewAdapter.notifyDataSetChanged();
}
2、弹框样式的兼容如下图所示,蓝色区域是键盘的高度,在屏幕进行旋转的时候,键盘的高度也是变化的,此时可能会出现遮挡住原本展示的内容,此处的处理方式是:让内容区域可以上下滑动。
3、摄像头位置的处理如下图所示,在屏幕旋转之后,摄像头可以出现在右下角,此时如果不对页面进行设置,那么就可能出现内容区域无法占据整个屏幕区域的问题,体验比较差,此处的处理方式是:设置页面沉浸式,摄像头可以合理地覆盖一部分内容。
我正在使用i18n从头开始构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在rubyonrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie
当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道rubyonrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim
我正在使用Postgres.app在OSX(10.8.3)上。我已经修改了我的PATH,以便应用程序的bin文件夹位于所有其他文件夹之前。Rammy:~phrogz$whichpg_config/Applications/Postgres.app/Contents/MacOS/bin/pg_config我已经安装了rvm并且可以毫无错误地安装pggem,但是当我需要它时我得到一个错误:Rammy:~phrogz$gem-v1.8.25Rammy:~phrogz$geminstallpgFetching:pg-0.15.1.gem(100%)Buildingnativeextension
我有一个应用程序正在从Ruby迁移到JRuby(由于需要通过Java提供更好的Web服务安全支持)。我使用的gem之一是daemons创建后台作业。问题在于它使用fork+exec来创建后台进程,但这对JRuby来说是禁忌。那么-是否有用于创建后台作业的替代gem/wrapper?我目前的想法是只从shell脚本调用rake并让rake任务永远运行......提前致谢,克里斯。更新我们目前正在使用几个与Java线程相关的包装器,即https://github.com/jmettraux/rufus-scheduler和https://github.com/philostler/acts
我的测试尝试访问网页并验证页面上是否存在某些元素。例如,它访问http://foo.com/homepage.html并检查Logo图像,然后访问http://bar.com/store/blah.html并检查页面上是否出现了某些文本。我的目标是访问经过Kerberos身份验证的网页。我发现Kerberos代码如下:主文件uri=URI.parse(Capybara.app_host)kerberos=Kerberos.new(uri.host)@kerberos_token=kerberos.encoded_tokenkerberos.rb文件classKerberosdefini
我在下面定义了api端点:paramsdorequires:ids,type:Array,desc:'Arrayofgroupids'end我无法从Swagger生成的UI传递数组。如果我输入[1,2,3,4]或ids%5b%5d=1&ids%5b%5d=2&ids%5b%5d=3然后两者都无效.如果我使用数组调用spec中的api,它就可以工作。我的客户想尝试Swagger的整个api,所以我想要一个适用于SwaggerUI的解决方案。 最佳答案 我对所有情况的解决方案:paramsdorequires:ids,type:Arra
我想在Rails中使用插件系统创建一个应用程序。潜在用户应该能够上传(或更好地从存储库安装)一个插件并安装它,使我的应用程序能够做更多的事情。这应该在没有FTP/SSH/对服务器的任何低级别访问的情况下完成。关于如何在Rails3中完成它,是否有任何好的gems或教程? 最佳答案 你看过http://edgeguides.rubyonrails.org/plugins.html了吗??它似乎不是100%兼容Rails3,但它可以帮助您入门。我看过的大多数插件文章都涉及Rails2。 关于