Giter Club home page Giter Club logo

verticalstepperform's Introduction

Vertical Stepper Form Library

issues pull requests contributors

This Android library implements a highly customizable vertical stepper form.

Demo

Demo picture

Support This Library

The creation (and maintenance) of this library requires time and effort. If you find it useful and want to support it, please use the link below:

Buy me a coffee!

How To Use It

1. Reference The Library

Add the library to your project via mavenCentral by adding the following in the app's build.gradle file:

dependencies {
    implementation 'com.ernestoyaquello.stepperform:vertical-stepper-form:2.7.0'
}

Make sure you are using AndroidX instead of the old support libraries; otherwise this library might not work.

2. Add The Form To Your Layout

Add the view VerticalStepperFormView to your layout using XML. For design purposes, it is recommended that you don't put anything else than this view in the layout of the screen that will contain the form:

<!-- new_user_form_activity.xml -->
<ernestoyaquello.com.verticalstepperform.VerticalStepperFormView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/stepper_form"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:form_circle_background_color="@color/colorPrimary"
    app:form_next_button_background_color="@color/colorPrimary"
    app:form_next_button_pressed_background_color="@color/colorPrimaryDark"/>

As you can see in this example, only the properties form_circle_background_color, form_next_button_background_color and form_next_button_pressed_background_color are being used to configure the form, but there are plenty of other ones that you can use to customize it as you please.

3. Define Your Steps

Each one of the fields of your form must be defined as a step.

To define a step, create a class that extends Step<T>, where T will be the type of the step's data (e.g., String if the data of the step is the user's name, Integer if it is the user's age, etc). For instance:

public class UserNameStep extends Step<String> {

    private EditText userNameView;

    public UserNameStep(String stepTitle) {
        super(stepTitle);
    }

    @Override
    protected View createStepContentLayout() {
        // Here we generate the view that will be used by the library as the content of the step.
        // In this case we do it programmatically, but we could also do it by inflating an XML layout.
        userNameView = new EditText(getContext());
        userNameView.setSingleLine(true);
        userNameView.setHint("Your Name");
        ...
        userNameView.addTextChangedListener(new TextWatcher() {
            ...
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                // Whenever the user updates the user name text, we update the state of the step.
                // The step will be marked as completed only if its data is valid, which will be
                // checked automatically by the form with a call to isStepDataValid().
                markAsCompletedOrUncompleted(true);
            }
        });

        return userNameView;
    }
    
    @Override
    protected IsDataValid isStepDataValid(String stepData) {
        // The step's data (i.e., the user name) will be considered valid only if it is longer than 
        // three characters. In case it is not, we will display an error message for feedback.
        // In an optional step, you should implement this method to always return a valid value.
        boolean isNameValid = stepData.length() >= 3;
        String errorMessage = !isNameValid ? "3 characters minimum" : "";

        return new IsDataValid(isNameValid, errorMessage);
    }

    @Override
    public String getStepData() {
        // We get the step's data from the value that the user has typed in the EditText view.
        Editable userName = userNameView.getText();
        return userName != null ? userName.toString() : "";
    }

    @Override
    public String getStepDataAsHumanReadableString() {
        // Because the step's data is already a human-readable string, we don't need to convert it.
        // However, we return "(Empty)" if the text is empty to avoid not having any text to display.
        // This string will be displayed in the subtitle of the step whenever the step gets closed.
        String userName = getStepData();        
        return !userName.isEmpty() ? userName : "(Empty)";
    }

    @Override
    protected void onStepOpened(boolean animated) {
        // This will be called automatically whenever the step gets opened.
    }

    @Override
    protected void onStepClosed(boolean animated) {
        // This will be called automatically whenever the step gets closed.
    }
    
    @Override
    protected void onStepMarkedAsCompleted(boolean animated) {
        // This will be called automatically whenever the step is marked as completed.
    }

    @Override
    protected void onStepMarkedAsUncompleted(boolean animated) {
        // This will be called automatically whenever the step is marked as uncompleted.
    }

    @Override
    protected void restoreStepData(String stepData) {
        // To restore the step after a configuration change, we restore the text of its EditText view.
        userNameView.setText(stepData);
    }
}

Most of the methods showed above will be called automatically by the library. For example, every time the user opens a step, the callback onStepOpened() will be invoked and the open step will be marked as completed or uncompleted automatically depending on the value returned by isStepDataValid(). Then, the callback onStepMarkedAsCompleted(), if applicable, will also be invoked.

It is worth noting that each step has a reference to the context accessible through getContext() and a reference to the form accessible through getFormView(), as well as several other useful methods.

4. Set Up The Form And Initialize It

Once you have defined all your steps, you will need to find the view of the form to set it up and initialize it:

public class CreateUserAccountActivity extends Activity implements StepperFormListener {

    private UserNameStep userNameStep;
    private UserEmailStep userEmailStep;
    private UserAgeStep userAgeStep;
    
    private VerticalStepperFormView verticalStepperForm;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.new_user_form_activity);

        // Create the steps.
        userNameStep = new UserNameStep("User Name");
        userEmailStep = new UserEmailStep("User Email");
        userAgeStep = new UserAgeStep("User Age");

        // Find the form view, set it up and initialize it.
        verticalStepperForm = findViewById(R.id.stepper_form);
        verticalStepperForm
            .setup(this, userNameStep, userEmailStep, userAgeStep)
            .init();
    }

    @Override
    public void onCompletedForm() {
        // This method will be called when the user clicks on the last confirmation button of the 
        // form in an attempt to save or send the data.
    }

    @Override
    public void onCancelledForm() {
        // This method will be called when the user clicks on the cancel button of the form.
    }

    @Override
    public void onStepAdded(int index, Step<?> addedStep) {
        // This will be called when a step is added dynamically through the form method addStep().
    }

    @Override
    public void onStepRemoved(int index) {
        // This will be called when a step is removed dynamically through the form method removeStep().
    }
}

As you can see in the code above, we set up the form by passing several parameters through the method setup():

  1. An implementation of the interface StepperFormListener (in this case, this listener is implemented by the activity, so we just send this as a parameter).
  2. The steps that will be displayed in the form: userNameStep, userEmailStep and userAgeStep in our example.

However, we can also customize the form just before initializing it:

verticalStepperForm
    .setup(this, userNameStep, userEmailStep, userAgeStep)
    .allowNonLinearNavigation(true)
    .displayBottomNavigation(false)
    .lastStepNextButtonText("Create User")
    ...
    .init();

There are many methods available to customize the form, but all the configuration options that you can specify via code are also available in XML, so it is up to you to set up the form in one way or another.

About The Listener

These are the two most important methods of the StepperFormListener:

onCompletedForm()

This method will get called when the user clicks on the last confirmation button of the form in an attempt to save/send the information, so we can use it to save or send the data of the form. It is worth noting that it will only get invoked if all the steps are marked as completed.

Just before calling this method, the form disables the navigation between steps, as well as all the buttons. To revert the form to normal (for example, because the data couldn't be saved and we want to re-activate the buttons of the form), it is necessary to call verticalStepperForm.cancelFormCompletionOrCancellationAttempt().

onCancelledForm()

This method will get called when the user clicks on the optional cancellation button of the last step in order to avoid saving/sending the data. We can use it to ask the user to confirm the cancellation, after which we could just close the form screen and navigate away from it.

Right before calling this method, the form disables the navigation between steps, as well as all the buttons. To revert the form to normal (for example, because the user decides not to cancel it), it is necessary to call verticalStepperForm.cancelFormCompletionOrCancellationAttempt().

Further Details

Check out the sample application code to see a more complete example of how this library can be used to create vertical stepper forms.

Contribution

Feel free to contribute to this library, any help will be welcomed!

License

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

verticalstepperform's People

Contributors

ernestoyaquello avatar wondercsabo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

verticalstepperform's Issues

Add method getView(stepNumber) to access children inputs' data - to set that step number status

I have a form, dynamically created, at each stepNumber, of which the fields are required or not depending on data. On each EditText I need all the form's EditTexts to check if all required fields are filled or not, the result of which will set a step's complete status.

At the moment, on creating views for steps, I am also saving Views in HashMap against stepNumber, so I can access all the views when any field in that stepNumber is edited.

The method could be called getView(stepNumber) or getForm(stepNumber)

Non linear?

Very nice library. Can it be configured as nonlinear where user can jump around to other steps out of order?

Crashing after image capture Kitkat 4.4.2

I use the stepper to display images captured from either camera or gallery. Once an image is captured from camera or image selected from gallery.

When coming back to my apps activity with the stepper form, the following method

protected void enableStepLayout(int stepNumber, boolean smoothieEnabling)

crashes on the first line of the method as "stepLayouts" is null.

Only appears to be an issue on 4.4.2. Could a fix be applied for this when possible.

Thanks

Stacktrace below.

Caused by: java.lang.NullPointerException
at ernestoyaquello.com.verticalstepperform.VerticalStepperFormLayout.enableStepLayout(VerticalStepperFormLayout.java:750)
at ernestoyaquello.com.verticalstepperform.VerticalStepperFormLayout.openStep(VerticalStepperFormLayout.java:676)
at ernestoyaquello.com.verticalstepperform.VerticalStepperFormLayout.goToStep(VerticalStepperFormLayout.java:334)
at ernestoyaquello.com.verticalstepperform.VerticalStepperFormLayout.restoreFormState(VerticalStepperFormLayout.java:890)
at ernestoyaquello.com.verticalstepperform.VerticalStepperFormLayout.onRestoreInstanceState(VerticalStepperFormLayout.java:1006)
at android.view.View.dispatchRestoreInstanceState(View.java:13722)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2844)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2850)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2850)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2850)
at android.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2850)
at android.view.View.restoreHierarchyState(View.java:13700)
at com.android.internal.policy.impl.PhoneWindow.restoreHierarchyState(PhoneWindow.java:1952)
at android.app.Activity.onRestoreInstanceState(Activity.java:983)
at android.app.Activity.performRestoreInstanceState(Activity.java:955)
at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1144)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2373)

Empty EditText Field

I have implemented your vertical stepper form but I have one issue that I can definitely not solve : my EditText created on the steps of createStepContentView() are always empty.
Anytime, it's impossible to access to the value, even thought through a textWatcher I can have the value input.
I followed exactly what you describe on your project, that's why I have now no more idea about the origin of that problem..
I hope you can help!
CreateInterventionActivity.txt

Give steps their own class

When using the library as of 0.9.x, we need to implement a lot of ugly switches.

Code would be much nicer if we could split the step logic into their own classes and the form would handle find the current step.

I got that interface which does the job:

public interface StepperFormStep {
    String getTitle();
    String getSubtitle();
    boolean isOptional();
    View createView();
    void onStepOpening(VerticalStepperFormLayout formLayout);
}

Then I have implementations such as:

public class StoreNameStep implements StepperFormStep {
    private Context context;
    private EditText name;

    public StoreNameStep(Context context) {
        this.context = context;
    }

    @Override
    public String getTitle() {
        return context.getString(R.string.wizard_store_step_title_name);
    }

    @Override
    public String getSubtitle() {
        return null;
    }

    @Override
    public boolean isOptional() {
        return false;
    }

    @Override
    public View createView() {
        name = new EditText(context);
        return name;
    }

    @Override
    public void onStepOpening(VerticalStepperFormLayout formLayout) {
        String name = this.name.getText().toString();

        if (Strings.isNullOrEmpty(name)) {
            String errorMessage = "You must indicate a store name";
            formLayout.setActiveStepAsUncompleted(errorMessage);
        } else {
            formLayout.setActiveStepAsCompleted();
        }
    }
}

My form looks like that:

public class EditStoreForm extends AbstractStepperForm {
    public EditStoreForm(Activity activity, VerticalStepperFormLayout stepperLayout) {
        super(activity, stepperLayout);
    }

    @NonNull
    @Override
    protected List<StepperFormStep> instantiateSteps() {
        return Lists.<StepperFormStep>newArrayList(
            new StoreNameStep(context)
        );
    }

    @Override
    public void sendData() {
    }
}

Setup in my fragment is a simple one-liner:

form = new EditStoreForm(getActivity(), formLayout);

And this class does the heavy lifting (that can be re-used for all my forms, and ideally it should be hidden by your library : users should just be providing forms and form steps):

public abstract class AbstractStepperForm implements VerticalStepperForm {

    protected Context context;
    protected VerticalStepperFormLayout formLayout;
    protected List<StepperFormStep> steps;

    public AbstractStepperForm(Activity activity, VerticalStepperFormLayout formLayout) {
        this.context = activity;
        this.formLayout = formLayout;
        this.steps = Lists.newArrayList(instantiateSteps());

        VerticalStepperFormLayout.Builder builder = VerticalStepperFormLayout.Builder.newInstance(formLayout, getStepTitles(), this, activity);
        initializeBuilder(builder);
        builder.init();
    }

    @NonNull
    protected abstract List<StepperFormStep> instantiateSteps();

    protected void initializeBuilder(VerticalStepperFormLayout.Builder builder) {
        builder
                .primaryColor(ContextCompat.getColor(context, R.color.colorPrimary))
                .primaryDarkColor(ContextCompat.getColor(context, R.color.colorPrimaryDark))
                .stepsSubtitles(getStepSubtitles());
    }

    @Override
    public View createStepContentView(int stepNumber) {
        StepperFormStep step = steps.get(stepNumber);
        return step.createView();
    }

    @Override
    public void onStepOpening(int stepNumber) {
        StepperFormStep step = steps.get(stepNumber);
        step.onStepOpening(formLayout);
    }

    @NonNull
    private String[] getStepTitles() {
        Collection<String> titles = Collections2.transform(steps, new Function<StepperFormStep, String>() {
            @Nullable
            @Override
            public String apply(StepperFormStep step) {
                return step.getTitle();
            }
        });

        return titles.toArray(new String[titles.size()]);
    }

    @NonNull
    private String[] getStepSubtitles() {
        Collection<String> subtitles = Collections2.transform(steps, new Function<StepperFormStep, String>() {
            @Nullable
            @Override
            public String apply(StepperFormStep step) {
                return step.getSubtitle();
            }
        });

        return subtitles.toArray(new String[subtitles.size()]);
    }
}

Then the only callback method needed is the sendData() callback.

StepperForm show this error "This step has already been initialized"

When i add two stepper view form in same activity the first stepper view working fine in first stepper view i use it as follwoing
verticalStepperForm1
.setup(listner1, stepperClassObject)
.init();
In second stepper view i use it same as above but in same activity. this give me error as "This step has already been initialized"

Change "Confirm data" text

Is it possible to change the text of the final, automatically added, step "Confirmation" and it's corresponding button? Without downloading the source that is. I could not find a way, and it's a quite vital function, especially if the app is in another language.

Navigation To Any Step

How can we navigate to any step i.e. independent from other.
If there is 5 steps, so how can I jump direct to step 3 from step 1 without navigating step 2.

Not following the design guidelines for vertical steppers

I think it is a good start, but it would look and feel much better following the Material Design Guidelines for Vertical Steppers.

Don’t embed steppers within steppers or use multiple steppers on one page.
Vertical Stepper Form has Vertical and Horizontal progress steppers combined.

Should follow all of the Design Specs

I think this library has a ton of potential. I will try to contribute as much as possible.

Cheers

Here is an example of the closest to the guidelines that I have created.

vertical steppers

Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

    mySteps = new String[]{"Test Name", "Marks Obtained", "Total Marks", "Date"};
    int colorPrimary = ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary);
    int colorPrimaryDark = ContextCompat.getColor(getApplicationContext(), R.color.colorPrimaryDark);

    VerticalStepperFormLayout verticalStepperForm =  (VerticalStepperFormLayout)findViewById(R.id.vertical_stepper_form);


    // Setting up and initializing the form
    VerticalStepperFormLayout.Builder.newInstance(verticalStepperForm, mySteps, this, this)
            .primaryColor(colorPrimary)
            .primaryDarkColor(colorPrimaryDark)
            .displayBottomNavigation(false) // It is true by default, so in this case this line is not necessary
            .init();

I am getting the error on the last line.

E/AndroidRuntime: FATAL EXCEPTION: main
Process: volunteer.upay.com.upay, PID: 7053
java.lang.RuntimeException: Unable to start activity ComponentInfo{volunteer.upay.com.upay/volunteer.upay.com.upay.Activities.AddStudentMarks}: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
at android.app.ActivityThread.access$800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.view.ViewGroup.addViewInner(ViewGroup.java:3936)
at android.view.ViewGroup.addView(ViewGroup.java:3786)
at android.view.ViewGroup.addView(ViewGroup.java:3727)
at android.view.ViewGroup.addView(ViewGroup.java:3700)
at ernestoyaquello.com.verticalstepperform.VerticalStepperFormLayout.setUpStep(VerticalStepperFormLayout.java:557)
at ernestoyaquello.com.verticalstepperform.VerticalStepperFormLayout.setUpSteps(VerticalStepperFormLayout.java:546)
at ernestoyaquello.com.verticalstepperform.VerticalStepperFormLayout.initializeForm(VerticalStepperFormLayout.java:512)
at ernestoyaquello.com.verticalstepperform.VerticalStepperFormLayout.initStepperForm(VerticalStepperFormLayout.java:487)
at ernestoyaquello.com.verticalstepperform.VerticalStepperFormLayout.initialiseVerticalStepperForm(VerticalStepperFormLayout.java:474)
at ernestoyaquello.com.verticalstepperform.VerticalStepperFormLayout$Builder.init(VerticalStepperFormLayout.java:1239)
at volunteer.upay.com.upay.Activities.AddStudentMarks.onCreate(AddStudentMarks.java:40)
at android.app.Activity.performCreate(Activity.java:5990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387) 
at android.app.ActivityThread.access$800(ActivityThread.java:151) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:135) 
at android.app.ActivityThread.main(ActivityThread.java:5254) 
at java.lang.reflect.Method.invoke(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:372) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 

Is it possible to add a hook to the buttons

Is it possible to add a hook to the buttons so I can do other stuff such as communicating the info back to the API?

(In my case I need access to each button and after confirmation button as well)

Localising labels is not supported

Hello Ernesto,

Localising the default labels used for the text elements is currently not supported. I have implemented the functionality and could provide a pull request, if you'd like to add this to the master?

Step content rendering issue.

Good day,

Each step of mine has quite a bit of content in.
To make it easier for the user each question asked would either show or hide the following question within the step (changing the visibility of the next question from 'gone' to 'visible').
This causes the next step to be rendered in a , for the lack of a better word, squished manner.
It also causes the 'form_last_button' to disappear completely from the screen.

Edit
Is it possible to call a sort of refresh method?
As soon as I click another step, and then back to the one in question (as mentioned above) everything renders fine.

Kind regards

Custom Continue message

what if i want to change button text => "CONTINUE" ??

for localization and someother reasons

Keyboard not showing for the first EditText

I am running Android N on Google Nexus 5X. I've created an Activity with few UI controls like EditText(s), Spinner and so on. Whenever I start the Activity the soft keyboard isn't shown for the first EditText but for the other EditText(s) and Spinners. It's working fine. I tried to programmatically open the soft keyboard in
onStepOpening(int) but it doesn't work.

Stepper state not restored in fragments

When I rotate the device, the stepper state is not restored.
I used this code:

`@Override
public void onSaveInstanceState(@nonnull Bundle outState) {

    //store the state of the stepper for screen rotations

    Parcelable parcelable = verticalStepperForm.onSaveInstanceState();

    //Parcelable stateOfStepper = verticalStepperForm.onSaveInstanceState();

    outState.putParcelable(STEPPER_STATE, parcelable);

    super.onSaveInstanceState(outState);

}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {

    if( savedInstanceState != null &&savedInstanceState.containsKey(STEPPER_STATE)) {


        Parcelable parcelable = savedInstanceState.getParcelable(STEPPER_STATE);


        //verticalStepperForm.goToStep(stateOfStepper, false);

        //onStepOpening(stateOfStepper);

        verticalStepperForm.onRestoreInstanceState(parcelable);




    }

    super.onActivityCreated(savedInstanceState);


}

`

return weekDays

How to return a non boolean value, but the day of the week?

upd: not relevant now

Cannot add a null child view to a ViewGroup

`val mySteps = arrayOf("Name", "Email", "Phone Number")
val colorPrimary = ContextCompat.getColor(applicationContext, R.color.colorPrimary)
val colorPrimaryDark = ContextCompat.getColor(applicationContext, R.color.colorPrimaryDark)

    VerticalStepperFormLayout.Builder.newInstance(vertical_stepper_form, mySteps, this, this)
            .primaryColor(colorPrimary)
            .primaryDarkColor(colorPrimaryDark)
            .displayBottomNavigation(true) // It is true by default, so in this case this line is not necessary
            .init()`

i try this code and get cannot add a null child view to a ViewGroup.
can you tell me where it wrong?

Getting error converting bytecode to dex

Error:Error converting bytecode to dex:
Cause: com.android.dex.DexException: Multiple dex files define Landroid/support/v4/os/ResultReceiver;
Error:com.android.dex.DexException: Multiple dex files define Landroid/support/v4/os/ResultReceiver;

How can I resolve this error?

Thanks about your library.

Request option to display all items expanded with the selected results from each of the step

Hello Ernesto,

I will probably use your component for a MVP app. Have you consider adding the option to display all steps expanded, so that the user can change the item of the step once they are already set.

Suppose this use case with 4 steps:

  1. User select all steps and confirm his selections (selections are displayed in another screen as a summary).
  2. User requires to update one of the selections or more (presses summary item to open the screen with the VerticalStepperLayout).
  3. User changes or updates the item already set. and confirm the changes.

I was planning on using another step like a fifth step of confirmation, which shows the summary, but i think the chance of showing all expanded would be much better.

Thanks for your hard work on this.

Custom width of element

It would be great to have element taking the all width of the screen (MATCH_PARENT) instead of fitting the content (I'm thinking about the EditText especially) because it looks weird on tablet where there is plenty of space but the field is very short.
When I put the layout to match parent, some problems of apparition come.
capture d ecran 2016-08-11 a 16 02 49

Steps do not support match_parent height

If the layout for an individual step uses the height 'match_parent', views will expand for ever and navigating back to a step will open it extremely slowly. Seen on Pixel 2 (Oreo)

Current work around is to use a fixed height or wrap_content.

Perhaps the library should automatically change match_parent to wrap_content where required, because users who haven't looked at the source may not be able to find the cause

Is it possible to add a custom font method?

Hi Ernesto,

Thank you so much for this library!

Do you think if is possible to add a method that let change the font type (custom font) to the Titles and Sub titles?

Thanks again for this library, it has help me a lot.

Keyboard Input Type Change Problem

Hi,

Every time an edittext with a different input type is focused, the page scroll to the top.

For example, I have one editbox for the name and another for the age. When I type the age and the keyboard is changed, the page scroll to the top.

How can I solve this?

Error inflating class ernestoyaquello.com.verticalstepperform.VerticalStepperFormView

Good day,

I'm getting the following error after including the library and using the layout structure described in the sample app.

java.lang.RuntimeException: Unable to start activity ComponentInfo{za.co.mjrsolutions.agrihost_mr_android/za.co.mjrsolutions.agrihost_mr_android.activities.report.CoreReport}: android.view.InflateException: Binary XML file line #1: Binary XML file line #1: Error inflating class ernestoyaquello.com.verticalstepperform.VerticalStepperFormView at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3319) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3415) at android.app.ActivityThread.access$1100(ActivityThread.java:229) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1821) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:7325) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) Caused by: android.view.InflateException: Binary XML file line #1: Binary XML file line #1: Error inflating class ernestoyaquello.com.verticalstepperform.VerticalStepperFormView at android.view.LayoutInflater.inflate(LayoutInflater.java:551) at android.view.LayoutInflater.inflate(LayoutInflater.java:429) at android.view.LayoutInflater.inflate(LayoutInflater.java:380) at android.support.v7.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:469) at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:140) at za.co.mjrsolutions.agrihost_mr_android.activities.report.CoreReport.onCreate(CoreReport.java:62) at android.app.Activity.performCreate(Activity.java:6904) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1136) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3266) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3415)  at android.app.ActivityThread.access$1100(ActivityThread.java:229)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1821)  at android.os.Handler.dispatchMessage(Handler.java:102)  at android.os.Looper.loop(Looper.java:148)  at android.app.ActivityThread.main(ActivityThread.java:7325)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)  Caused by: android.view.InflateException: Binary XML file line #1: Error inflating class ernestoyaquello.com.verticalstepperform.VerticalStepperFormView at android.view.LayoutInflater.createView(LayoutInflater.java:657) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:776) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716) at android.view.LayoutInflater.inflate(LayoutInflater.java:498) at android.view.LayoutInflater.inflate(LayoutInflater.java:429)  at android.view.LayoutInflater.inflate(LayoutInflater.java:380)  at android.support.v7.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:469)  at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:140)  at za.co.mjrsolutions.agrihost_mr_android.activities.report.CoreReport.onCreate(CoreReport.java:62)  at android.app.Activity.performCreate(Activity.java:6904)  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1136)  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3266)  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3415)  at android.app.ActivityThread.access$1100(ActivityThread.java:229)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1821)  at android.os.Handler.dispatchMessage(Handler.java:102)  at android.os.Looper.loop(Looper.java:148)  at android.app.ActivityThread.main(ActivityThread.java:7325)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)  Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Constructor.newInstance(Native Method) at android.view.LayoutInflater.createView(LayoutInflater.java:631) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:776)  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716)  at android.view.LayoutInflater.inflate(LayoutInflater.java:498)  at android.view.LayoutInflater.inflate(LayoutInflater.java:429)  at android.view.LayoutInflater.inflate(LayoutInflater.java:380)  at android.support.v7.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:469)  at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:140)  at za.co.mjrsolutions.agrihost_mr_android.activities.report.CoreReport.onCreate(CoreReport.java:62)  at android.app.Activity.performCreate(Activity.java:6904)  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1136)  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3266)  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3415)  at android.app.ActivityThread.access$1100(ActivityThread.java:229)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1821)  at android.os.Handler.dispatchMessage(Handler.java:102)  at android.os.Looper.loop(Looper.java:148)  at android.app.ActivityThread.main(ActivityThread.java:7325)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)  Caused by: android.view.InflateException: Binary XML file line #35: Binary XML file line #35: Error inflating class androidx.appcompat.widget.AppCompatImageButton at android.view.LayoutInflater.inflate(LayoutInflater.java:551) at android.view.LayoutInflater.inflate(LayoutInflater.java:429) at ernestoyaquello.com.verticalstepperform.VerticalStepperFormView.onConstructed(VerticalStepperFormView.java:455) at ernestoyaquello.com.verticalstepperform.VerticalStepperFormView.<init>(VerticalStepperFormView.java:54) at java.lang.reflect.Constructor.newInstance(Native Method)  at android.view.LayoutInflater.createView(LayoutInflater.java:631)  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:776)  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716)  at android.view.LayoutInflater.inflate(LayoutInflater.java:498)  at android.view.LayoutInflater.inflate(LayoutInflater.java:429)  at android.view.LayoutInflater.inflate(LayoutInflater.java:380)  at android.support.v7.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:469)  at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:140)  at za.co.mjrsolutions.agrihost_mr_android.activities.report.CoreReport.onCreate(CoreReport.java:62)  at android.app.Activity.performCreate(Activity.java:6904)  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1136)  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3266)  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3415)  at android.app.ActivityThread.access$1100(ActivityThread.java:229)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1821)  at android.os.Handler.dispatchMessage(Handler.java:102)  at android.os.Looper.loop(Looper.java:148)  at android.app.ActivityThread.main(ActivityThread.java:7325)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)  Caused by: android.view.InflateException: Binary XML file line #35: Error inflating class androidx.appcompat.widget.AppCompatImageButton at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:788) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716) at android.view.LayoutInflater.rInflate(LayoutInflater.java:847) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810) at android.view.LayoutInflater.rInflate(LayoutInflater.java:855) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:810) at android.view.LayoutInflater.inflate(LayoutInflater.java:527) at android.view.LayoutInflater.inflate(LayoutInflater.java:429)  at ernestoyaquello.com.verticalstepperform.VerticalStepperFormView.onConstructed(VerticalStepperFormView.java:455)  at ernestoyaquello.com.verticalstepperform.VerticalStepperFormView.<init>(VerticalStepperFormView.java:54)  at java.lang.reflect.Constructor.newInstance(Native Method)  at android.view.LayoutInflater.createView(LayoutInflater.java:631)  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:776)  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:716)  at android.view.LayoutInflater.inflate(LayoutInflater.java:498)  at android.view.LayoutInflater.inflate(LayoutInflater.java:429)  at android.view.LayoutInflater.inflate(LayoutInflater.java:380)  at android.support.v7.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:469)  at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:140)  at za.co.mjrsolutions.agrihost_mr_android.activities.report.CoreReport.onCreate(CoreReport.java:62)  at android.app.Activity.performCreate(Activity.java:6904)  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1136)  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3266)  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3415)  at android.app.ActivityThread.access$1100(ActivityThread.java:229)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1821)  at android.os.Handler.dispatchMessage(Handler.java:102)  at android.os.Looper.loop(Looper.java:148)  at android.app.ActivityThread.main(ActivityThread.java:7325)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)  Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.appcompat.widget.AppCompatImageButton" on path: DexPathList[[zip file "/data/app/za.co.mjrsolutions.agrihost_mr_android-2/base.apk", zip file "/data/app/za.co.mjrsolutions.agrihost_mr_andro

Kind regards

Remove Attribute application@allowBackup value

It's for an application not a library ?

Error:Execution failed for task ':app:processDebugManifest'.
> Manifest merger failed : Attribute application@allowBackup value=(false) from AndroidManifest.xml:16:9-36
    is also present at [com.ernestoyaquello.stepperform:vertical-stepper-form:0.9.9] AndroidManifest.xml:12:9-35 value=(true).
``

Make stepContentView match parent width in stepContent

First, thanks for making everything protected and putting things in fine grained methods so it's very easy to extend and alter the behavior of this library.

I'm not sure if this is a bug or just an improvement, but I think that the individual stepContentViews should be just the width of their parent stepContent and not wrap it's contents which is the standard behavior with addView(). This way you run into trouble if you want to make full width components inside a stepContentView without using actual dp values.

I suggest changing setUpStep(int stepNumber) to:

protected void setUpStep(int stepNumber) {
        LinearLayout stepLayout = createStepLayout(stepNumber);
        if (stepNumber < numberOfSteps) {
            // The content of the step is the corresponding custom view previously created
            RelativeLayout stepContent = (RelativeLayout) stepLayout.findViewById(R.id.step_content);
            // start new
            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT); 
            stepContent.addView(stepContentViews.get(stepNumber), params);
            // end new
        } else {
            setUpStepLayoutAsConfirmationStepLayout(stepLayout);
        }
        addStepToContent(stepLayout);
}

Remove Continue Button

There are scenarios where we need to handle the navigation of the Stepper ourself like for example when a step has two buttons, instead of having to click on one of the buttons and then click continue, we can navigate to the next step on the initial button click.

So would it be possible to hide/remove the continue button for certain steps?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.