代码拉取完成,页面将自动刷新
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.
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
1. 开源生态
2. 协作、人、软件
3. 评估模型