1 Star 4 Fork 2

CHINASOFT4_OHOS / VerticalStepperForm

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
Apache-2.0

VerticalStepperForm

项目介绍

  • 项目名称:VerticalStepperForm
  • 所属系列:openharmony的第三方组件适配移植
  • 功能:一个高度可定制的垂直步进表单。
  • 项目移植状态:选择时间钟表有差异
  • 调用差异:无
  • 开发版本:sdk6,DevEco Studio 2.2 Beta1
  • 基线版本:Release V2.5.0

效果演示

效果演示

安装教程

1.在项目根目录下的build.gradle文件中,

allprojects {
   repositories {
       maven {
           url 'https://s01.oss.sonatype.org/content/repositories/releases/'
       }
   }
}

2.在entry模块的build.gradle文件中,

dependencies {
   implementation('com.gitee.chinasoft_ohos:VerticalStepperForm:1.0.0')
   ......  
}

在sdk6,DevEco Studio 2.2 Beta1下项目可直接运行 如无法运行,删除项目.gradle,.idea,build,gradle,build.gradle文件, 并依据自己的版本创建新项目,将新项目的对应文件复制到根目录下

使用说明

VerticalStepperFormView使用 XML将视图添加到您的布局。出于设计目的,建议您不要在包含表单的屏幕布局中放置除此视图以外的任何内容:

<!-- ability_new_alarm_form.xml -->
<ernestoyaquello.com.verticalstepperform.VerticalStepperFormView
        ohos:id="$+id:stepper_form"
        ohos:width="match_parent"
        ohos:height="match_parent"
        app:form_last_button_text="$string:add_alarm"
        app:form_circle_background_color="$color:colorPrimary"
        app:form_next_button_background_color="$color:colorPrimary"
        app:form_next_button_pressed_background_color="$color:colorPrimaryDark"
        app:form_display_cancel_button_in_last_step="true"
        app:form_cancel_button_background_color="$color:transparent"
        app:form_cancel_button_pressed_background_color="$color:transparent"
        app:form_cancel_button_text_color="$color:colorPrimary"
        app:form_cancel_button_pressed_text_color="$color:colorPrimaryDark"/>
要定义一个步骤,请创建一个扩展类Step<T>,其中T将是步骤数据的类型(例如,String如果步骤的数据是用户的姓名,Integer如果是用户的年龄等)。例如:
public abstract class Step<T> {
    private String originalNextButtonText;
    private String title;
    private String subtitle;
    private String nextButtonText;
    private String errorMessage;
    private boolean isCompleted;
    private boolean isOpen;
    private boolean isHasError;
    private Component stepLayout;
    private Component contentLayout;
    private VerticalStepperFormView formView;

    private List<InternalFormStepListener> internalListeners;

    /**
     * Step
     *
     * @param title
     */
    protected Step(String title) {
        this(title, "");
    }

    /**
     * Step
     *
     * @param title
     * @param subtitle
     */
    protected Step(String title, String subtitle) {
        this(title, subtitle, "");
    }

    /**
     * Step
     *
     * @param title
     * @param subtitle
     * @param nextButtonText
     */
    protected Step(String title, String subtitle, String nextButtonText) {
        this.title = title;
        this.subtitle = subtitle;
        this.nextButtonText = nextButtonText;
        this.originalNextButtonText = nextButtonText;
        this.errorMessage = "";
        this.internalListeners = new ArrayList<>();
    }

    /**
     * Gets the data of this step (i.e., the information that the user has filled in for this field).
     *
     * @return The step data.
     */
    public abstract T getStepData();

    /**
     * Gets the data of this step (i.e., the information that the user has filled in for this field)
     * as a human-readable string. When the option isDisplayStepDataInSubtitleOfClosedSteps is
     * activated, the text returned by this method will be the one displayed in the step's subtitle.
     *
     * @return The step data as a human-readable string.
     */
    public abstract String getStepDataAsHumanReadableString();

    /**
     * Restores the step data. Useful for when restoring the state of the form.
     *
     * @param data The step data to restore.
     */
    public abstract void restoreStepData(T data);

    /**
     * Determines whether the step data (i.e., the information the user has filled up in this field)
     * is valid or not.
     *
     * @return True if the data is valid; false otherwise.
     */
    public boolean isStepDataValid() {
        IsDataValid isDataValid = isStepDataValid(getStepData());
        isDataValid = isDataValid == null ? new IsDataValid(true) : isDataValid;

        return isDataValid.isValid();
    }

    /**
     * Returns an instance of IsDataValid that indicates whether the step data is valid or not.
     * This instance also contains an optional error message for when the data is not valid.
     *
     * @param stepData The data whose validity will be checked.
     * @return An instance of IsDataValid with information about the validity of the data.
     */
    protected abstract IsDataValid isStepDataValid(T stepData);

    /**
     * This method will be called automatically by the form in order to get the layout of the step.
     *
     * @return The step's layout.
     */
    protected abstract Component createStepContentLayout();

    /**
     * This method will be called every time the step is opened.
     *
     * @param isAnimated True if the step was opened using animations; false otherwise.
     * Generally, it will only be false if the step was opened on loading or on
     * restoration.
     */
    protected abstract void onStepOpened(boolean isAnimated);

    /**
     * This method will be called every time the step is closed.
     *
     * @param isAnimated True if the step was closed using animations; false otherwise.
     * Generally, it will only be false if the step was closed on loading or on
     * restoration.
     */
    protected abstract void onStepClosed(boolean isAnimated);

    /**
     * This method will be called every time the step is marked as isCompleted.
     *
     * @param isAnimated True if the step was marked as isCompleted using animations; false otherwise.
     * Generally, it will only be false if the step was marked as isCompleted on
     * loading or on restoration.
     */
    protected abstract void onStepMarkedAsCompleted(boolean isAnimated);

    /**
     * This method will be called every time the step is marked as uncompleted.
     *
     * @param isAnimated True if the step was marked as uncompleted using animations; false otherwise.
     * Generally, it will only be false if the step was marked as uncompleted on
     * loading or on restoration.
     */
    protected abstract void onStepMarkedAsUncompleted(boolean isAnimated);

    /**
     * Gets the title of this step.
     *
     * @return The title.
     */
    public String getTitle() {
        return title == null ? "" : title;
    }

    /**
     * Gets the subtitle of this step.
     *
     * @return The subtitle.
     */
    public String getSubtitle() {
        return subtitle == null ? "" : subtitle;
    }

    /**
     * Gets the text for the step's button.
     *
     * @return The button text.
     */
    public String getNextButtonText() {
        return nextButtonText == null ? "" : nextButtonText;
    }

    /**
     * Gets the current error message of this step.
     *
     * @return The error message.
     */
    public String getErrorMessage() {
        return errorMessage == null ? "" : errorMessage;
    }

    /**
     * Determines whether the step is marked as isCompleted or not.
     *
     * @return True if the step is marked as isCompleted; false otherwise.
     */
    public boolean isCompleted() {
        return isCompleted;
    }

    /**
     * Determines whether the step is isOpen or not.
     *
     * @return True if the step is isOpen; false otherwise.
     */
    public boolean isOpen() {
        return isOpen;
    }

    /**
     * Returns whether or not the step is currently considered to be in an error state because its
     * data is invalid.
     *
     * Please note that even if the data is invalid, this method will only return true after the
     * step has been opened at least once (or after its completion state has been updated manually).
     * This way, a step with invalid data whose content hasn't been seen by the user won't appear
     * to be in an error state until the user opens it for the first time.
     * On this regard, it is also worth noting that this method won't update the state of the step;
     * it will just return the value that indicates whether the step is currently in an error state.
     *
     * @return True if the step is in an error state; false otherwise.
     */
    public boolean hasError() {
        return isHasError;
    }

    /**
     * Gets the content layout of the step, which was generated on createStepContentLayout(), if any.
     *
     * @return The step's content layout.
     */
    public Component getContentLayout() {
        return contentLayout;
    }

    /**
     * This method returns the entire step layout.
     *
     * Please note that this is not the layout of the step's content; this layout is for the entire
     * step and includes the header, the "Next" button, etc.
     *
     * @return The entire step layout.
     */
    public Component getEntireStepLayout() {
        return stepLayout;
    }

    /**
     * Gets the position of the step within the form, counting from 0.
     *
     * @return The position of the step.
     */
    public int getPosition() {
        return formView.getStepPosition(this);
    }

    /**
     * Gets the instance of the vertical stepper form that this step belongs to.
     *
     * @return The instance of the form.
     */
    public VerticalStepperFormView getFormView() {
        return formView;
    }

    /**
     * Gets the context of the form.
     *
     * @return The context.
     */
    public Context getContext() {
        return formView.getContext();
    }

    /**
     * Marks the step as isCompleted or uncompleted depending on whether the step data is valid or not.
     * It should be called every time the step data changes.
     *
     * @param isUseAnimations True to animate the changes in the views, false to not.
     * @return True if the step was marked as isCompleted; false otherwise.
     */
    public boolean markAsCompletedOrUncompleted(boolean isUseAnimations) {
        return markAsCompletedOrUncompletedInternal(isUseAnimations, false);
    }

    /**
     * Marks the step as isCompleted.
     *
     * @param isUseAnimations True to animate the changes in the views, false to not.
     */
    public void markAsCompleted(boolean isUseAnimations) {
        updateStepCompletionState(true, "", isUseAnimations);
    }

    /**
     * Marks the step as uncompleted.
     *
     * @param errorMessage The optional error message that explains why the step is uncompleted.
     * @param isUseAnimations True to animate the changes in the views, false to not.
     */
    public void markAsUncompleted(String errorMessage, boolean isUseAnimations) {
        updateStepCompletionState(false, errorMessage, isUseAnimations);
    }

    /**
     * Sets the title of the step, updating the view if necessary,
     *
     * @param title The new title of the step.
     * @param isUseAnimations Determines whether or not the necessary layout changes should be animated.
     */
    protected void updateTitle(String title, boolean isUseAnimations) {
        this.title = title == null ? "" : title;

        onUpdatedTitle(isUseAnimations);
    }

    /**
     * Sets the subtitle of the step, updating the view if necessary,
     *
     * @param subtitle The new subtitle of the step.
     * @param isUseAnimations Determines whether or not the necessary layout changes should be animated.
     */
    protected void updateSubtitle(String subtitle, boolean isUseAnimations) {
        this.subtitle = subtitle == null ? "" : subtitle;

        onUpdatedSubtitle(isUseAnimations);
    }

    /**
     * Sets the text of the of the step's button, updating the view if necessary,
     *
     * @param buttonText The new text for the button of the step.
     * @param isUseAnimations Determines whether or not the necessary layout changes should be animated.
     */
    protected void updateNextButtonText(String buttonText, boolean isUseAnimations) {
        this.nextButtonText = buttonText == null ? "" : buttonText;

        onUpdatedButtonText(isUseAnimations);
    }

    private void updateErrorMessage(String errorMessage, boolean isUseAnimations) {
        this.errorMessage = errorMessage == null ? "" : errorMessage;

        onUpdatedErrorMessage(isUseAnimations);
    }

    private void updateStepCompletionState(boolean isCompleted, String errorMessage, boolean isUseAnimations) {
        this.isCompleted = isCompleted;

        updateErrorMessage(errorMessage, isUseAnimations);
        onUpdatedStepCompletionState(isUseAnimations);
        if (isCompleted) {
            onStepMarkedAsCompleted(isUseAnimations);
        } else {
            onStepMarkedAsUncompleted(isUseAnimations);
        }
    }

    private void updateStepVisibility(boolean isVisibility, boolean isUseAnimations) {
        isOpen = isVisibility;

        onUpdatedStepVisibility(isUseAnimations);
        if (isVisibility) {
            onStepOpened(isUseAnimations);
        } else {
            onStepClosed(isUseAnimations);
        }
    }

    private void onUpdatedTitle(boolean isUseAnimations) {
        for (InternalFormStepListener listener: internalListeners) {
            listener.onUpdatedTitle(getPosition(), isUseAnimations);
        }
    }

    private void onUpdatedSubtitle(boolean isUseAnimations) {
        for (InternalFormStepListener listener: internalListeners) {
            listener.onUpdatedSubtitle(getPosition(), isUseAnimations);
        }
    }

    private void onUpdatedButtonText(boolean isUseAnimations) {
        for (InternalFormStepListener listener: internalListeners) {
            listener.onUpdatedButtonText(getPosition(), isUseAnimations);
        }
    }

    private void onUpdatedErrorMessage(boolean isUseAnimations) {
        for (InternalFormStepListener listener: internalListeners) {
            listener.onUpdatedErrorMessage(getPosition(), isUseAnimations);
        }
    }

    private void onUpdatedStepCompletionState(boolean isUseAnimations) {
        for (InternalFormStepListener listener: internalListeners) {
            listener.onUpdatedStepCompletionState(getPosition(), isUseAnimations);
        }
    }

    private void onUpdatedStepVisibility(boolean isUseAnimations) {
        for (InternalFormStepListener listener: internalListeners) {
            listener.onUpdatedStepVisibility(getPosition(), isUseAnimations);
        }
    }

    String getOriginalNextButtonText() {
        return originalNextButtonText == null ? "" : originalNextButtonText;
    }

    void addListenerInternal(InternalFormStepListener listener) {
        if (!internalListeners.contains(listener)) {
            internalListeners.add(listener);
        }
    }

    void openInternal(boolean isUseAnimations) {
        if (!isOpen) {
            updateStepVisibility(true, isUseAnimations);
        }
    }

    void closeInternal(boolean isUseAnimations) {
        if (isOpen) {
            updateStepVisibility(false, isUseAnimations);
        }
    }

    void restoreErrorState(boolean isHasError) {
        this.isHasError = isHasError;
    }

    boolean markAsCompletedOrUncompletedInternal(boolean isUseAnimations, boolean isAddingNewStep) {
        IsDataValid isDataValid = isStepDataValid(getStepData());
        isDataValid = isDataValid == null ? new IsDataValid(true) : isDataValid;
        boolean isValid = isDataValid.isValid();

        if (isCompleted != isValid) {
            if (isValid) {
                isHasError = false;
                markAsCompleted(isUseAnimations);
            } else {
                isHasError = !isAddingNewStep;
                markAsUncompleted(isDataValid.getErrorMessage(), isUseAnimations);
            }
        } else {
            isHasError = !isAddingNewStep && !isValid;
            updateErrorMessage(isValid ? "" : isDataValid.getErrorMessage(), isUseAnimations);
        }

        return isValid;
    }

    void initializeStepInternal(Component stepLayout, VerticalStepperFormView formView) {
        this.stepLayout = stepLayout;
        this.formView = formView;
    }

    void setContentLayoutInternal(Component contentLayout) {
        this.contentLayout = contentLayout;
    }

    /**
     * This class holds information about whether the data is valid in a boolean. It also includes
     * an optional error message for when the data turns out to be invalid.
     */
    /**
     * This class holds information about whether the data is valid in a boolean. It also includes
     * an optional error message for when the data turns out to be invalid.
     *
     * @since 2021-07-14
     */
    protected static class IsDataValid {
        private boolean isValid;
        private String errorMessage;

        /**
         * IsDataValid
         *
         * @param isValid
         */
        public IsDataValid(boolean isValid) {
            this(isValid, "");
        }

        /**
         * IsDataValid
         *
         * @param isValid
         * @param errorMessage
         */
        public IsDataValid(boolean isValid, String errorMessage) {
            this.isValid = isValid;
            this.errorMessage = errorMessage;
        }

        /**
         * Determines whether the data is valid or not.
         *
         * @return True if the data is valid; false otherwise.
         */
        public boolean isValid() {
            return isValid;
        }

        /**
         * Gets the optional error message, if any.
         *
         * @return The optional error message, or null if none.
         */
        public String getErrorMessage() {
            return errorMessage;
        }
    }

    /**
     * Internal listener that will be used to notify both the form and the step helper
     * about any changes on this step so they can update accordingly.
     *
     * @since 2021-07-14
     */
    interface InternalFormStepListener {
        void onUpdatedTitle(int stepPosition, boolean isUseAnimations);

        void onUpdatedSubtitle(int stepPosition, boolean isUseAnimations);

        void onUpdatedButtonText(int stepPosition, boolean isUseAnimations);

        void onUpdatedErrorMessage(int stepPosition, boolean isUseAnimations);

        void onUpdatedStepCompletionState(int stepPosition, boolean isUseAnimations);

        void onUpdatedStepVisibility(int stepPosition, boolean isUseAnimations);
    }
}public abstract class Step<T> {
    private String originalNextButtonText;
    private String title;
    private String subtitle;
    private String nextButtonText;
    private String errorMessage;
    private boolean isCompleted;
    private boolean isOpen;
    private boolean isHasError;
    private Component stepLayout;
    private Component contentLayout;
    private VerticalStepperFormView formView;

    private List<InternalFormStepListener> internalListeners;

    /**
     * Step
     *
     * @param title
     */
    protected Step(String title) {
        this(title, "");
    }

    /**
     * Step
     *
     * @param title
     * @param subtitle
     */
    protected Step(String title, String subtitle) {
        this(title, subtitle, "");
    }

    /**
     * Step
     *
     * @param title
     * @param subtitle
     * @param nextButtonText
     */
    protected Step(String title, String subtitle, String nextButtonText) {
        this.title = title;
        this.subtitle = subtitle;
        this.nextButtonText = nextButtonText;
        this.originalNextButtonText = nextButtonText;
        this.errorMessage = "";
        this.internalListeners = new ArrayList<>();
    }

    /**
     * Gets the data of this step (i.e., the information that the user has filled in for this field).
     *
     * @return The step data.
     */
    public abstract T getStepData();

    /**
     * Gets the data of this step (i.e., the information that the user has filled in for this field)
     * as a human-readable string. When the option isDisplayStepDataInSubtitleOfClosedSteps is
     * activated, the text returned by this method will be the one displayed in the step's subtitle.
     *
     * @return The step data as a human-readable string.
     */
    public abstract String getStepDataAsHumanReadableString();

    /**
     * Restores the step data. Useful for when restoring the state of the form.
     *
     * @param data The step data to restore.
     */
    public abstract void restoreStepData(T data);

    /**
     * Determines whether the step data (i.e., the information the user has filled up in this field)
     * is valid or not.
     *
     * @return True if the data is valid; false otherwise.
     */
    public boolean isStepDataValid() {
        IsDataValid isDataValid = isStepDataValid(getStepData());
        isDataValid = isDataValid == null ? new IsDataValid(true) : isDataValid;

        return isDataValid.isValid();
    }

    /**
     * Returns an instance of IsDataValid that indicates whether the step data is valid or not.
     * This instance also contains an optional error message for when the data is not valid.
     *
     * @param stepData The data whose validity will be checked.
     * @return An instance of IsDataValid with information about the validity of the data.
     */
    protected abstract IsDataValid isStepDataValid(T stepData);

    /**
     * This method will be called automatically by the form in order to get the layout of the step.
     *
     * @return The step's layout.
     */
    protected abstract Component createStepContentLayout();

    /**
     * This method will be called every time the step is opened.
     *
     * @param isAnimated True if the step was opened using animations; false otherwise.
     * Generally, it will only be false if the step was opened on loading or on
     * restoration.
     */
    protected abstract void onStepOpened(boolean isAnimated);

    /**
     * This method will be called every time the step is closed.
     *
     * @param isAnimated True if the step was closed using animations; false otherwise.
     * Generally, it will only be false if the step was closed on loading or on
     * restoration.
     */
    protected abstract void onStepClosed(boolean isAnimated);

    /**
     * This method will be called every time the step is marked as isCompleted.
     *
     * @param isAnimated True if the step was marked as isCompleted using animations; false otherwise.
     * Generally, it will only be false if the step was marked as isCompleted on
     * loading or on restoration.
     */
    protected abstract void onStepMarkedAsCompleted(boolean isAnimated);

    /**
     * This method will be called every time the step is marked as uncompleted.
     *
     * @param isAnimated True if the step was marked as uncompleted using animations; false otherwise.
     * Generally, it will only be false if the step was marked as uncompleted on
     * loading or on restoration.
     */
    protected abstract void onStepMarkedAsUncompleted(boolean isAnimated);

    /**
     * Gets the title of this step.
     *
     * @return The title.
     */
    public String getTitle() {
        return title == null ? "" : title;
    }

    /**
     * Gets the subtitle of this step.
     *
     * @return The subtitle.
     */
    public String getSubtitle() {
        return subtitle == null ? "" : subtitle;
    }

    /**
     * Gets the text for the step's button.
     *
     * @return The button text.
     */
    public String getNextButtonText() {
        return nextButtonText == null ? "" : nextButtonText;
    }

    /**
     * Gets the current error message of this step.
     *
     * @return The error message.
     */
    public String getErrorMessage() {
        return errorMessage == null ? "" : errorMessage;
    }

    /**
     * Determines whether the step is marked as isCompleted or not.
     *
     * @return True if the step is marked as isCompleted; false otherwise.
     */
    public boolean isCompleted() {
        return isCompleted;
    }

    /**
     * Determines whether the step is isOpen or not.
     *
     * @return True if the step is isOpen; false otherwise.
     */
    public boolean isOpen() {
        return isOpen;
    }

    /**
     * Returns whether or not the step is currently considered to be in an error state because its
     * data is invalid.
     *
     * Please note that even if the data is invalid, this method will only return true after the
     * step has been opened at least once (or after its completion state has been updated manually).
     * This way, a step with invalid data whose content hasn't been seen by the user won't appear
     * to be in an error state until the user opens it for the first time.
     * On this regard, it is also worth noting that this method won't update the state of the step;
     * it will just return the value that indicates whether the step is currently in an error state.
     *
     * @return True if the step is in an error state; false otherwise.
     */
    public boolean hasError() {
        return isHasError;
    }

    /**
     * Gets the content layout of the step, which was generated on createStepContentLayout(), if any.
     *
     * @return The step's content layout.
     */
    public Component getContentLayout() {
        return contentLayout;
    }

    /**
     * This method returns the entire step layout.
     *
     * Please note that this is not the layout of the step's content; this layout is for the entire
     * step and includes the header, the "Next" button, etc.
     *
     * @return The entire step layout.
     */
    public Component getEntireStepLayout() {
        return stepLayout;
    }

    /**
     * Gets the position of the step within the form, counting from 0.
     *
     * @return The position of the step.
     */
    public int getPosition() {
        return formView.getStepPosition(this);
    }

    /**
     * Gets the instance of the vertical stepper form that this step belongs to.
     *
     * @return The instance of the form.
     */
    public VerticalStepperFormView getFormView() {
        return formView;
    }

    /**
     * Gets the context of the form.
     *
     * @return The context.
     */
    public Context getContext() {
        return formView.getContext();
    }

    /**
     * Marks the step as isCompleted or uncompleted depending on whether the step data is valid or not.
     * It should be called every time the step data changes.
     *
     * @param isUseAnimations True to animate the changes in the views, false to not.
     * @return True if the step was marked as isCompleted; false otherwise.
     */
    public boolean markAsCompletedOrUncompleted(boolean isUseAnimations) {
        return markAsCompletedOrUncompletedInternal(isUseAnimations, false);
    }

    /**
     * Marks the step as isCompleted.
     *
     * @param isUseAnimations True to animate the changes in the views, false to not.
     */
    public void markAsCompleted(boolean isUseAnimations) {
        updateStepCompletionState(true, "", isUseAnimations);
    }

    /**
     * Marks the step as uncompleted.
     *
     * @param errorMessage The optional error message that explains why the step is uncompleted.
     * @param isUseAnimations True to animate the changes in the views, false to not.
     */
    public void markAsUncompleted(String errorMessage, boolean isUseAnimations) {
        updateStepCompletionState(false, errorMessage, isUseAnimations);
    }

    /**
     * Sets the title of the step, updating the view if necessary,
     *
     * @param title The new title of the step.
     * @param isUseAnimations Determines whether or not the necessary layout changes should be animated.
     */
    protected void updateTitle(String title, boolean isUseAnimations) {
        this.title = title == null ? "" : title;

        onUpdatedTitle(isUseAnimations);
    }

    /**
     * Sets the subtitle of the step, updating the view if necessary,
     *
     * @param subtitle The new subtitle of the step.
     * @param isUseAnimations Determines whether or not the necessary layout changes should be animated.
     */
    protected void updateSubtitle(String subtitle, boolean isUseAnimations) {
        this.subtitle = subtitle == null ? "" : subtitle;

        onUpdatedSubtitle(isUseAnimations);
    }

    /**
     * Sets the text of the of the step's button, updating the view if necessary,
     *
     * @param buttonText The new text for the button of the step.
     * @param isUseAnimations Determines whether or not the necessary layout changes should be animated.
     */
    protected void updateNextButtonText(String buttonText, boolean isUseAnimations) {
        this.nextButtonText = buttonText == null ? "" : buttonText;

        onUpdatedButtonText(isUseAnimations);
    }

    private void updateErrorMessage(String errorMessage, boolean isUseAnimations) {
        this.errorMessage = errorMessage == null ? "" : errorMessage;

        onUpdatedErrorMessage(isUseAnimations);
    }

    private void updateStepCompletionState(boolean isCompleted, String errorMessage, boolean isUseAnimations) {
        this.isCompleted = isCompleted;

        updateErrorMessage(errorMessage, isUseAnimations);
        onUpdatedStepCompletionState(isUseAnimations);
        if (isCompleted) {
            onStepMarkedAsCompleted(isUseAnimations);
        } else {
            onStepMarkedAsUncompleted(isUseAnimations);
        }
    }

    private void updateStepVisibility(boolean isVisibility, boolean isUseAnimations) {
        isOpen = isVisibility;

        onUpdatedStepVisibility(isUseAnimations);
        if (isVisibility) {
            onStepOpened(isUseAnimations);
        } else {
            onStepClosed(isUseAnimations);
        }
    }

    private void onUpdatedTitle(boolean isUseAnimations) {
        for (InternalFormStepListener listener: internalListeners) {
            listener.onUpdatedTitle(getPosition(), isUseAnimations);
        }
    }

    private void onUpdatedSubtitle(boolean isUseAnimations) {
        for (InternalFormStepListener listener: internalListeners) {
            listener.onUpdatedSubtitle(getPosition(), isUseAnimations);
        }
    }

    private void onUpdatedButtonText(boolean isUseAnimations) {
        for (InternalFormStepListener listener: internalListeners) {
            listener.onUpdatedButtonText(getPosition(), isUseAnimations);
        }
    }

    private void onUpdatedErrorMessage(boolean isUseAnimations) {
        for (InternalFormStepListener listener: internalListeners) {
            listener.onUpdatedErrorMessage(getPosition(), isUseAnimations);
        }
    }

    private void onUpdatedStepCompletionState(boolean isUseAnimations) {
        for (InternalFormStepListener listener: internalListeners) {
            listener.onUpdatedStepCompletionState(getPosition(), isUseAnimations);
        }
    }

    private void onUpdatedStepVisibility(boolean isUseAnimations) {
        for (InternalFormStepListener listener: internalListeners) {
            listener.onUpdatedStepVisibility(getPosition(), isUseAnimations);
        }
    }

    String getOriginalNextButtonText() {
        return originalNextButtonText == null ? "" : originalNextButtonText;
    }

    void addListenerInternal(InternalFormStepListener listener) {
        if (!internalListeners.contains(listener)) {
            internalListeners.add(listener);
        }
    }

    void openInternal(boolean isUseAnimations) {
        if (!isOpen) {
            updateStepVisibility(true, isUseAnimations);
        }
    }

    void closeInternal(boolean isUseAnimations) {
        if (isOpen) {
            updateStepVisibility(false, isUseAnimations);
        }
    }

    void restoreErrorState(boolean isHasError) {
        this.isHasError = isHasError;
    }

    boolean markAsCompletedOrUncompletedInternal(boolean isUseAnimations, boolean isAddingNewStep) {
        IsDataValid isDataValid = isStepDataValid(getStepData());
        isDataValid = isDataValid == null ? new IsDataValid(true) : isDataValid;
        boolean isValid = isDataValid.isValid();

        if (isCompleted != isValid) {
            if (isValid) {
                isHasError = false;
                markAsCompleted(isUseAnimations);
            } else {
                isHasError = !isAddingNewStep;
                markAsUncompleted(isDataValid.getErrorMessage(), isUseAnimations);
            }
        } else {
            isHasError = !isAddingNewStep && !isValid;
            updateErrorMessage(isValid ? "" : isDataValid.getErrorMessage(), isUseAnimations);
        }

        return isValid;
    }

    void initializeStepInternal(Component stepLayout, VerticalStepperFormView formView) {
        this.stepLayout = stepLayout;
        this.formView = formView;
    }

    void setContentLayoutInternal(Component contentLayout) {
        this.contentLayout = contentLayout;
    }

    /**
     * This class holds information about whether the data is valid in a boolean. It also includes
     * an optional error message for when the data turns out to be invalid.
     */
    /**
     * This class holds information about whether the data is valid in a boolean. It also includes
     * an optional error message for when the data turns out to be invalid.
     *
     * @since 2021-07-14
     */
    protected static class IsDataValid {
        private boolean isValid;
        private String errorMessage;

        /**
         * IsDataValid
         *
         * @param isValid
         */
        public IsDataValid(boolean isValid) {
            this(isValid, "");
        }

        /**
         * IsDataValid
         *
         * @param isValid
         * @param errorMessage
         */
        public IsDataValid(boolean isValid, String errorMessage) {
            this.isValid = isValid;
            this.errorMessage = errorMessage;
        }

        /**
         * Determines whether the data is valid or not.
         *
         * @return True if the data is valid; false otherwise.
         */
        public boolean isValid() {
            return isValid;
        }

        /**
         * Gets the optional error message, if any.
         *
         * @return The optional error message, or null if none.
         */
        public String getErrorMessage() {
            return errorMessage;
        }
    }

    /**
     * Internal listener that will be used to notify both the form and the step helper
     * about any changes on this step so they can update accordingly.
     *
     * @since 2021-07-14
     */
    interface InternalFormStepListener {
        void onUpdatedTitle(int stepPosition, boolean isUseAnimations);

        void onUpdatedSubtitle(int stepPosition, boolean isUseAnimations);

        void onUpdatedButtonText(int stepPosition, boolean isUseAnimations);

        void onUpdatedErrorMessage(int stepPosition, boolean isUseAnimations);

        void onUpdatedStepCompletionState(int stepPosition, boolean isUseAnimations);

        void onUpdatedStepVisibility(int stepPosition, boolean isUseAnimations);
    }
}
定义完所有步骤后,您将需要找到表单的视图以对其进行设置和初始化:
public class NewAlarmFormAbility extends Ability implements StepperFormListener {
    private static final int BARLENGTH = 260;
    private static final int BARWIDTH = 10;
    private static final int RIMWIDTH = 10;
    private static final int SPINSPEED = 50;
    private static final int INT_2 = 2;
    private static final int INT_3 = 3;
    private static final int INT_1000 = 1000;
    private static final int INT_100 = 100;
    private static final int INT_10001 = 10001;
    private AlarmNameStep nameStep;
    private AlarmDescriptionStep descriptionStep;
    private AlarmTimeStep timeStep;
    private AlarmDaysStep daysStep;
    private VerticalStepperFormView verticalStepperFormView;
    private DependentLayout dlDialog;
    private DependentLayout dlPwDialog;
    private ProgressWheel pw;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_new_alarm_form);
        verticalStepperFormView = (VerticalStepperFormView) findComponentById(ResourceTable.Id_stepper_form);
        String[] stepTitles = new String[]{"Name", "Description", "Time", "Week schedule"};

        nameStep = new AlarmNameStep(stepTitles[0]);
        descriptionStep = new AlarmDescriptionStep(stepTitles[1]);
        timeStep = new AlarmTimeStep(stepTitles[INT_2],
                (DependentLayout) findComponentById(ResourceTable.Id_dl_time_picker));
        daysStep = new AlarmDaysStep(stepTitles[INT_3]);

        verticalStepperFormView
                .setup(this, nameStep, descriptionStep, timeStep, daysStep)
                .init();
        dlDialog = (DependentLayout) findComponentById(ResourceTable.Id_dl_dialog);
        Text positive = (Text) findComponentById(ResourceTable.Id_btn_positive);
        positive.setClickedListener(component -> goBack(null));
        Text negative = (Text) findComponentById(ResourceTable.Id_btn_negative);
        negative.setClickedListener(component -> dlDialog.setVisibility(Component.HIDE));

        dlPwDialog = (DependentLayout) findComponentById(ResourceTable.Id_dl_progress_dialog);
        pw = (ProgressWheel) findComponentById(ResourceTable.Id_pw);
        pw.setBarColor(Color.getIntColor("#1976d2"));
        pw.setRimColor(Color.getIntColor("#ffffff"));
        pw.setBarLength(BARLENGTH);
        pw.setBarWidth(BARWIDTH);
        pw.setRimWidth(RIMWIDTH);
        pw.setSpinSpeed(SPINSPEED);
    }

    @Override
    public void onCompletedForm() {
        dlPwDialog.setVisibility(Component.VISIBLE);
        pw.startSpinning();
        verticalStepperFormView.cancelFormCompletionOrCancellationAttempt();
        final Thread dataSavingThread = saveData();
        dlPwDialog.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                try {
                    dataSavingThread.interrupt();
                } catch (RuntimeException e) {
                    // No need to do anything here
                } finally {
                    verticalStepperFormView.cancelFormCompletionOrCancellationAttempt();
                }
                pw.stopSpinning();
                dlPwDialog.setVisibility(Component.HIDE);
            }
        });
    }

    private Thread saveData() {
        // Fake data saving effect
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(INT_1000);
                sendAlarmDataBack();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        thread.start();
        return thread;
    }

    private void sendAlarmDataBack() {
        getMainTaskDispatcher().delayDispatch(new Runnable() {
            @Override
            public void run() {
                Alarm alarm = new Alarm(
                        nameStep.getStepData(),
                        descriptionStep.getStepData(),
                        timeStep.getStepData().hour,
                        timeStep.getStepData().minutes,
                        daysStep.getStepData());
                goBack(alarm);
            }
        }, INT_100);
    }

    private void goBack(Alarm alarm) {
        Intent intent = new Intent();
        setResult(INT_10001, intent);
        GlobalData.getInstance().setAlarm(alarm);
        terminateAbility();
    }

    @Override
    public void onCancelledForm() {
        dlDialog.setVisibility(Component.VISIBLE);
    }
}
verticalStepperForm
    .setup(this, userNameStep, userEmailStep, userAgeStep)
    .allowNonLinearNavigation(true)
    .displayBottomNavigation(false)
    .lastStepNextButtonText("Create User")
    ...
    .init();

测试信息

CodeCheck代码测试无异常

CloudTest代码测试无异常

病毒安全检测通过

当前版本demo功能与原组件基本无差异

版本迭代

1.0.0

版权和许可信息

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.
Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2018 Julio Ernesto Rodríguez Cabañas 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.

简介

一个高度可定制的垂直步进表单 展开 收起
Java
Apache-2.0
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Java
1
https://gitee.com/chinasoft4_ohos/VerticalStepperForm.git
git@gitee.com:chinasoft4_ohos/VerticalStepperForm.git
chinasoft4_ohos
VerticalStepperForm
VerticalStepperForm
master

搜索帮助