Skip to content

Instantly share code, notes, and snippets.

@cutiko
Last active February 6, 2019 19:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cutiko/00f9fb656caa010f9986b282b8cbc4b3 to your computer and use it in GitHub Desktop.
Save cutiko/00f9fb656caa010f9986b282b8cbc4b3 to your computer and use it in GitHub Desktop.
How to create forms
public class AvailableBox extends Checkbox implements FormField, OnCheckChangeListener {
private ErrorCallback errorCallback;
private User user;
//use the constructor with 1 argument for using only on java and the constructor with 2 arguments for using on xml
public AvailableBox(...) {
//you can add any MUST HAVE behaviour in the constructor
setOnCheckChangedListener(this);
}
@Override
onCheckChangedListener(boolean cbValue) {
//This user is the same that in the View
user.setAvailability(cbValue)
if (cbValue) {
removeError();
} else {
setError();
}
}
@Override
boolean isValid() {
if (!isChecked) {
setError();
errorCallback.fiedlPosition(getBottom());
}
return isChecked();
}
@Override
void setError(){//set the error somehow}
@Override
void removeError(){//remove error somehow}
@Override
void setErrorCallback(ErrorCallback errorCallback) {
this.errorCallback = errorCallback;
}
void setUser(User user) {
this.user = user;
}
}
class ComplexField extends LinearLayout implements FormField {
//The same one argument or two arguments
public ComplexField() {
LayoutInflater inflater = LayoutInflater.from(context);
//true is auto attach
inflater.inflate(R.layout.your_layout, this, true);
//this way you can add a more complex layout if needed
}
}
//This interface has every common aspect between fields
interface FormField {
//is valid can be called by the View (activity or fragment)
boolean isValid();
void setError();
void removeError();
//this callback can be triggered when isValid is false and make the View scroll to the missing field
void setCallback(ErrorCallback errorCallback);
//for this example, let's say we are creating a user
void setUser(User user);
interface ErrorCallback {
void fiedlPosition(int bottom);
}
}
public class TheActivity extends AppCompatActivity implements FormField.ErrorCallback {
private List<FormField> fields = new ArrayList();
private User user;
onCreate() {
//here you can iterate all the views, something like
LinearLayout container = findViewById(R.id.root);
user = (User) getIntent().getSerializableExtra(USER);
user = (user != null) ? user : new User();
//either editing or creating, we can pass the object and change it on the fields
//java objects work as reference, if any field change the user, then this user change as weel
viewIterator(container, user);
}
//This make using fragments easy, anyway you can find your form fields programatically
private void viewIterator(ViewGroup group, User user) {
int count = group.getChildCount();
for (int i = 0; i < count; i++) {
if (group.childAt(i) instanceOf FormField) {
FormField field = group.childAt(i);
//We can pass the user so the field will modify it
field.setUser(user);
fields.add(field);
}
if (group.childAt(i) instanceOf VieGroupd) viewIterator(group.childAt(i), user);
}
}
//Call something like this when the user press the save button
private void onSave() {
for (FormField field : fields) {
if (!field.isValid()) return
}
//validation say everything is ok, now save
//we can user the field user because is modified by each field
sendData(user);
}
@Override
void fiedlPosition(int bottom) {
//remember to scroll to the field, this will be triggered on inner field validation
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment