Dannie
Dannie

Reputation: 175

Views are gone when ConstraintSet.applyTo

I'm trying to extend the ConstraintLayout functionality to have a ProgressBar with fullscreen translucent background color. The idea is that I could reuse this layout and call hideLoading() and showLoading(). Progress bar has to be centered.

Problem is: when constraintSet.applyTo(this) is called all views that had ConstraintSet.connect(...) on them are GONE, or not drawn. As all operations on them are ignored and they are not displayed on the screen at all.

Here is what I have :

public class ConstraintLayout extends android.support.constraint.ConstraintLayout {

    private View background;
    private ProgressBar progressBar;

    public ConstraintLayout(Context context) {
        super(context);
        addLoader();
    }

    public ConstraintLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        addLoader();
    }

    public ConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        addLoader();
    }

    private void addLoader(){
        int wrapContent = LayoutParams.WRAP_CONTENT;
        int matchParent = LayoutParams.MATCH_PARENT;

        ConstraintSet constraintSet = new ConstraintSet();
        constraintSet.clone(this);

        background = new View(getContext());
        background.setBackgroundColor(getResources()
                .getColor(R.color.background_loader_color));
        background.setId(generateViewId());
        addView(background, new ConstraintLayout.LayoutParams(matchParent, matchParent));

        constraintSet.connect(background.getId(), ConstraintSet.TOP, 
                ConstraintSet.PARENT_ID, ConstraintSet.TOP, 0);
        constraintSet.connect(background.getId(), ConstraintSet.BOTTOM, 
                ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM, 0);
        constraintSet.connect(background.getId(), ConstraintSet.LEFT, 
                ConstraintSet.PARENT_ID, ConstraintSet.LEFT, 0);
        constraintSet.connect(background.getId(), ConstraintSet.RIGHT, 
                ConstraintSet.PARENT_ID, ConstraintSet.RIGHT, 0);

        progressBar = new ProgressBar(getContext(), null, android.R.attr.progressBarStyleLarge);
        progressBar.setId(generateViewId());
        addView(progressBar, new ConstraintLayout.LayoutParams(wrapContent, wrapContent));

        constraintSet.connect(progressBar.getId(), ConstraintSet.TOP, 
                ConstraintSet.PARENT_ID, ConstraintSet.TOP, 0);
        constraintSet.connect(progressBar.getId(), ConstraintSet.BOTTOM, 
                ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM, 0);
        constraintSet.connect(progressBar.getId(), ConstraintSet.START, 
                ConstraintSet.PARENT_ID, ConstraintSet.START, 0);
        constraintSet.connect(progressBar.getId(), ConstraintSet.END, 
                ConstraintSet.PARENT_ID, ConstraintSet.END, 0);

        constraintSet.applyTo(this);
    }

    public void showLoading(){
        background.setVisibility(VISIBLE);
        progressBar.setVisibility(VISIBLE);
    }

    public void hideLoading(){
        background.setVisibility(GONE);
        progressBar.setVisibility(GONE);
    }
}

Here is what I have img and what I want what i want

Upvotes: 5

Views: 2963

Answers (2)

Cheticamp
Cheticamp

Reputation: 62831

There has been a change since 1.1.0-beta5 that now requires code to explicitly set the width and height of views to manually defined a ConstraintLayout and its ConstraintSet. I am not sure exactly the reason, but the code goes as follows:

After connecting background add

    constraintSet.constrainWidth(background.getId(),matchParent);
    constraintSet.constrainHeight(background.getId(),matchParent);

After connecting progressBar add

    constraintSet.constrainWidth(progressBar.getId(),wrapContent);
    constraintSet.constrainHeight(progressBar.getId(),wrapContent);

Without this code, the width and height of the views are not set within the constraints. This code makes sure the width and height are set.

See the documentation for constraining width and height.

Upvotes: 2

Martin Marconcini
Martin Marconcini

Reputation: 27226

The problem seems to be that you’re setting your Background constraints as MATCH_PARENT which is invalid in ConstraintLayouts. I assume you meant LayoutParams.MATCH_CONSTRAINT.

I assume you want your layout to “simulate” this XML:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:id="@+id/bkg"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@android:color/holo_red_dark"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

Which looks like:

enter image description here

tl;dr: Change the line int matchParent = LayoutParams.MATCH_PARENT; to int matchParent = LayoutParams.MATCH_CONSTRAINT;

UPDATE: I tried my own solution and didn’t work, so I spend a few minutes looking at your code and found the problem. I am using ConstraintLayout 1.1.0

  1. Yes, use MATCH CONSTRAINT.
  2. You are setting constraints for views that don’t yet exist… so I recreated your “custom layout” and here’s mine:

Main Activity just inflates this via setContentView(R.layout.demo_layout)

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
                                             xmlns:app="http://schemas.android.com/apk/res-auto"
                                             xmlns:tools="http://schemas.android.com/tools"
                                             android:id="@+id/root"
                                             android:layout_width="match_parent"
                                             android:layout_height="match_parent"
                                             tools:context=".MainActivity"
    >
    <com.so.ProgressConstraintLayout
        android:id="@+id/demo_progress_container"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        />
</android.support.constraint.ConstraintLayout>

And my ProgressConstraintLayout… which I copied from yours and modified:

package com.so;

import android.content.Context;
import android.support.constraint.ConstraintLayout;
import android.support.constraint.ConstraintSet;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ProgressBar;

public class ProgressConstraintLayout extends ConstraintLayout {

    private View background;
    private ProgressBar progressBar;

    public ProgressConstraintLayout(Context context) {
        super(context);
        addLoader();
    }

    public ProgressConstraintLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        addLoader();
    }

    public ProgressConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        addLoader();
    }

    private void addLoader() {
        int wrapContent = LayoutParams.WRAP_CONTENT;
        int matchConstraint = LayoutParams.MATCH_CONSTRAINT;

        ConstraintSet constraintSet = new ConstraintSet();

        background = new View(getContext());
        background.setBackgroundColor(getResources().getColor(android.R.color.holo_blue_bright, getContext().getTheme()));
        background.setId(generateViewId());
        addView(background, new ConstraintLayout.LayoutParams(matchConstraint, matchConstraint));

        progressBar = new ProgressBar(getContext(), null, android.R.attr.progressBarStyleLarge);
        progressBar.setIndeterminate(true);
        progressBar.setId(generateViewId());
        addView(progressBar, new ConstraintLayout.LayoutParams(wrapContent, wrapContent));

        constraintSet.clone(this);
        constraintSet.connect(background.getId(), ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP);
        constraintSet.connect(background.getId(), ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM);
        constraintSet.connect(background.getId(), ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START);
        constraintSet.connect(background.getId(), ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END);
        constraintSet.connect(progressBar.getId(), ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP);
        constraintSet.connect(progressBar.getId(), ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM);
        constraintSet.connect(progressBar.getId(), ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START);
        constraintSet.connect(progressBar.getId(), ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END);
        constraintSet.applyTo(this);
    }

    public void showLoading() {
        background.setVisibility(VISIBLE);
        progressBar.setVisibility(VISIBLE);
    }

    public void hideLoading() {
        background.setVisibility(GONE);
        progressBar.setVisibility(GONE);
    }
}

And if you’re wondering how it looks… pretty boring but who am I to judge: enter image description here

Upvotes: 4

Related Questions