将View.GONE更改为View.VISIBLE之后,以编程方式构建叠加层布局

时间:2019-01-27 15:01:14

标签: android android-layout

我正在尝试为我的应用构建动态帮助覆盖屏幕。对于具有可见性或不可见性的元素,我有一些基本的用法,但是当元素最初为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>

1 个答案:

答案 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()方法获取孩子的命中率   父母坐标中的矩形(可触摸区域)。

来自Manage touch events in a ViewGroup