我正在尝试为我的应用构建动态帮助覆盖屏幕。对于具有可见性或不可见性的元素,我有一些基本的用法,但是当元素最初为Visibility.GONE
(在构建视图之前将其更改为可见)时,它们仍然位于位置 0, 0 ,尺寸为 0x0 。
我尝试添加简短的wait()
循环,onLayoutChangedListener()
和getViewTreeObserver().addOnGlobalLayoutListener()
,但它们什么也没做。
in onOptionsSelected():
HelpUtils helpUtils = new HelpUtils(mView, requireContext());
final View helpView = helpUtils.getHelpView();
final View mainLayout = helpUtils.getMainLayout();
View shiftFragment = mainLayout.findViewById(R.id.current_shift_layout);
Map<View, Integer> visibilityMap = new HashMap<>();
for (int i = 0; i < ((ViewGroup) shiftFragment).getChildCount(); i++) {
View child = ((ViewGroup)shiftFragment).getChildAt(i);
visibilityMap.put(child, child.getVisibility());
child.setVisibility(View.VISIBLE);
}
final ViewGroup viewGroup = helpUtils.getHelpViewGroup(targets);
if (firstTime) {
((FrameLayout)helpView).addView(viewGroup);
}
helpView.setVisibility(View.VISIBLE);
HelpUtils类:
public class HelpUtils {
final private View mView;
final private Context mContext;
public HelpUtils(View view, Context context) {
mView = view;
mContext = context;
}
public View getMainLayout() {
return mView.getRootView().findViewById(R.id.main_layout);
}
public View getHelpView() {
return getMainLayout().findViewById(R.id.help_view);
}
private void recursiveWalkViews(ViewGroup viewGroup, SparseArray<View> result, Set<Integer> targets) {
for (int i = 0; i < viewGroup.getChildCount(); i++) {
View v = viewGroup.getChildAt(i);
if(v instanceof ViewGroup) {
recursiveWalkViews(((ViewGroup) v), result, targets);
} else {
if (targets.contains(v.getId())) {
result.put(v.getId(), v);
}
}
}
}
public SparseArray<View> getViewMap(Set<Integer> targets) {
SparseArray<View> map = new SparseArray<>();
ViewGroup view = (ViewGroup) mView;
recursiveWalkViews(view, map, targets);
return map;
}
private int getActionBarHeight() {
int[] textSizeAttr = new int[]{R.attr.actionBarSize};
TypedArray a = mContext.obtainStyledAttributes(new TypedValue().data, textSizeAttr);
int height = a.getDimensionPixelSize(0, 0);
a.recycle();
return height;
}
/**
* Match the layout of a new {@link TextView} to the layout of an existing view.
* @param source The {@link View} to be matched to.
* @param txt The text for the new {@link TextView}
* @return A new {@link TextView}
*/
public TextView matchParams(View source, String txt) {
int x, y;
float sp, size;
int[] location = new int[2];
int offset;
source.getLocationInWindow(location);
x = location[0];
y = location[1];
offset = source.getPaddingLeft();
size = ((TextView) source).getTextSize();
sp = size/mContext.getResources().getDisplayMetrics().scaledDensity;
TextView textView = new TextView(mContext);
textView.setWidth(source.getWidth() - source.getPaddingRight());
textView.setTextSize(14);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
if(source instanceof MaterialButton) {
params.topMargin = y + offset + ((MaterialButton)source).getPaddingBottom() - getActionBarHeight();
} else {
params.topMargin = y + offset - getActionBarHeight();
}
params.leftMargin = x + 8;
textView.setLayoutParams(params);
textView.setBackgroundColor(mContext.getResources().getColor(android.R.color.white));
textView.setText(txt);
return textView;
}
public ViewGroup getHelpViewGroup(Map<Integer, String> helpViews) {
FrameLayout layout = new FrameLayout(mContext);
SparseArray<View> views = getViewMap(helpViews.keySet());
List<TextView> textViews = new ArrayList<>(views.size());
for (int i = 0; i < views.size(); i++) {
View view = views.valueAt(i);
textViews.add(matchParams(views.valueAt(i), helpViews.get(views.keyAt(i))));
}
for (TextView textView : textViews) {
layout.addView(textView);
}
return layout;
}
}
Layout Inspector显示重叠视图是在 0,0 处绘制的,宽度为 0 ,但是更改为VISIBLE的视图在正确的位置。 / p>
答案 0 :(得分:0)
在onOptionsSelected()
中,将新创建的视图从目标视图中封装到Runnable()
中(我猜是shiftFragment
,因为这是将所有视图设置为{{1 }}。
基本上进行以下更改。
之前:
View.VISIBLE
之后:
for (int i = 0; i < ((ViewGroup) shiftFragment).getChildCount(); i++) {
View child = ((ViewGroup)shiftFragment).getChildAt(i);
visibilityMap.put(child, child.getVisibility());
child.setVisibility(View.VISIBLE);
}
final ViewGroup viewGroup = helpUtils.getHelpViewGroup(targets);
if (firstTime) {
((FrameLayout)helpView).addView(viewGroup);
}
helpView.setVisibility(View.VISIBLE);
下面的代码段执行以下操作:
获取父视图并在UI线程上发布Runnable。 此 确保父母在给孩子打电话之前先布置孩子 getHitRect()方法。 getHitRect()方法获取孩子的命中率 父母坐标中的矩形(可触摸区域)。