如何在没有代码的情况下隐藏Android布局xml中部分可见的视图?
回答前请仔细阅读问题强> 假设我有两种观点:如何在没有代码的情况下隐藏Android布局xml中部分可见的视图?,android,android-layout,android-widget,android-linearlayout,android-appwidget,Android,Android Layout,Android Widget,Android Linearlayout,Android Appwidget,回答前请仔细阅读问题 假设我有两种观点: 底部第一个(黄色) second(青色)填充上面的视图的其余部分first 父视图的大小是动态的 当父级高度动态设置为第一列中的值时,如何实现下面预期的列UI?请注意,部分可见的视图是如何隐藏而不是裁剪的 约束条件 任何代码都不可能,我知道可以通过以下方法解决问题: second.setVisibility(second.getHeight()
底部第一个
(黄色)second
(青色)填充上面的视图的其余部分first
- 任何代码都不可能,我知道可以通过以下方法解决问题:
但是我没有访问second.setVisibility(second.getHeight()
的权限,因此解决方案必须是纯xml。getHeight()
可以通过
轻松地只编写UI状态代码remoteview
- 基于上述不允许自定义视图,不t甚至库,只允许基本布局管理器:
,框架布局
,线性布局
,相对布局
网格布局
或者作为最后手段,选择一种高级方法:
,ViewFlipper
,ListView
,GridView
或StackView
AdapterViewFlipper
和layout\u宽度
是动态的layout\u高度
在本例中,我修复了它,因此很容易尝试不同的变体。上图是
layout\u height
更改为显示值,模拟我想要处理的可能性
TextView
,但它通常适用于任何视图
RelativeLayout
和LinearLayout
实现,但它们都表现为图片上的实际列
相对布局
线性布局
如果这是RemoteView/widget,请尝试使用多个布局文件。扩展并重写该方法。在此函数中,您需要执行以下操作:
Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
int minHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
然后以最小高度为例,确定哪种布局最适合充气。在制作小部件时非常有用。虽然没有真正报告实际值,但我找到了解决方法。请注意,这并不能真正解决手头的问题,而是一个相当复杂的解决方法
想法的来源
调查
当用户广播点击时,它将。正如您在bnds=[281756][5331071]
中看到的,视图是533-281=252
宽和1071-756=315
高,这些是像素,Galaxy S4是一个设备,因此252x315/3=84x105
这正是我对小部件单元大小的经验观察
给定的边界取决于给定给setOnClickPendingContent
的viewId
,因此要获得单元格大小,需要在布局中的根视图上附加挂起的意图。我的小部件有一个“点击刷新”监听器,我可以安全地将它附加到根布局。还有一些视图确实有pendingent
s,但是这些视图覆盖了根布局,因此它们的意图将被广播,就像常规的onClickListener
s一样
解决方案
现在,这意味着我们知道确切的单元大小,基于此,可以手动计算某些视图的大小(对于更简单的布局)。本质上,我们有办法获得根.getHeight()
,我们可以将第一个的大小“硬编码”为R.dimen.firstHeight
,并由此计算是否显示第一个,第二个
或者,像@AndrewOrobator建议的那样,利用这些边界:为适合大小的布局充气
需要用户交互
唯一的问题是,这至少需要用户交互一次。当窗口小部件主机发送更新时,没有边界,因此用户必须点击一个视图,这样我们就有了大小。我会解决这个问题,强迫用户点击一次视图(就在他们将小部件安装到主页之后):
“我没有访问getHeight()的权限”为什么?@mmlooloo:因为上没有View
getter。远程进程(窗口小部件主机)没有反馈,这是一种方式,这就是为什么我只要求布局xml。它的16加-24表示顶部边缘的填充为8。@danny117我不确定我是否理解,请复制我的一次尝试来测试它。然后进行您建议的更改,并通过将layout\u height=“16dp”
更改为图像上的值来比较视觉效果。很明显,顶部边缘有填充物,填充物是如何消失的?我也对这个谜题的答案感兴趣。对于这种类型的问题,多个布局文件是个好主意。我的目标是API 10,这种方法就是API 16。即使我在新版本中使用它,我想我也无法获得正确的单元格大小。我知道三星Galaxy S4有84dp x 105dp
widget单元,但我无法接近这个数字。我想它给了我我在
上指定的最小高度。我将再次尝试这些最小值/最大值并报告。我再次检查(所有值都是dp
):“OnAppWidgetOptionChanged(appWidgetID,Bundle[{appWidgetMaxHeight=89,appWidgetCategory=1,appWidgetMaxWidth=89,appWidgetMinHeight=68,appWidgetMinWidth=68}])68x68
-89x89
与84x105
相去甚远。是的,小部件就是这样。它们给出的大小是近似的,甚至在不同的设备或发射器之间都不稳定。
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="64dp" (actually fill_parent, but fix it for sake of simplicity)
android:layout_height="fill_parent" (first column on picture)
android:layout_gravity="center"
android:background="#666"
android:orientation="vertical"
tools:ignore="HardcodedText,RtlHardcoded"
>
<TextView
android:id="@+id/second"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#80ff"
android:text="Second"
android:gravity="center"
/>
<TextView
android:id="@+id/first"
android:layout_width="wrap_content"
android:layout_height="16dp"
android:layout_gravity="right"
android:background="#8ff0"
android:text="First"
/>
</LinearLayout>
Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
int minHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
Normal update from the widget host
26061-26061/net.twisterrob.app.debug V/TAG﹕ onReceive(Intent { act=android.appwidget.action.APPWIDGET_UPDATE flg=0x10000010 cmp=net.twisterrob.app.debug/net.twisterrob.app.AppWidgetProvider (has extras) } (Bundle[{appWidgetIds=[I@42b14090}]))
26061-26061/net.twisterrob.app.debug V/TAG﹕ onUpdate([483])
User tap with setOnClickPendingIntent
26061-26061/net.twisterrob.app.debug V/TAG﹕ onReceive(Intent { act=android.appwidget.action.APPWIDGET_UPDATE flg=0x10000010 cmp=net.twisterrob.app.debug/net.twisterrob.app.AppWidgetProvider bnds=[281,756][533,1071] (has extras) } (Bundle[{appWidgetIds=[I@42b14090}]))
26061-26061/net.twisterrob.app.debug V/TAG﹕ onUpdate([483])
@Override
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(intent.getAction())) {
for (int appWidgetId : getAppWidgetIds(intent)) {
Rect storedBounds = getSizeFromPreferences(appWidgetId);
Rect sourceBounds = intent.getSourceBounds();
if (storedBounds == null && sourceBounds != null) {
// no stored size, but we just received one, save it
setSizeToPreferences(appWidgetId, sourceBounds);
storedBounds = sourceBounds;
}
if (storedBounds == null) {
// we didn't have a stored size, neither received one
// force the user to interact with the widget once so we have a size
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_tap_to_refresh);
views.setOnClickPendingIntent(R.id.root, createRefresh(context, appWidgetId));
AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId, views);
} else {
// update as usual, and use the bounds from getSizeFromPreferences(appWidgetId)
onUpdate(context, AppWidgetManager.getInstance(context), new int[] {appWidgetId});
}
}
} else {
super.onReceive(context, intent);
}
}
private @NonNull int[] getAppWidgetIds(Intent intent) {
int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
if (appWidgetIds == null) {
appWidgetIds = new int[0];
}
return appWidgetIds;
}
private @NonNull PendingIntent createRefresh(Context context, int appWidgetId) {
Intent intent = new Intent(context, MyAppWidgetProvider.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetId);
return PendingIntent.getBroadcast(context, appWidgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}