On ViewControllers #3830
Unanswered
westnordost
asked this question in
Repository Maintenance
Replies: 1 comment
-
For reference: implementation in #3885 |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
So, I have lately been thinking about how to make user interfaces (found in quest forms) more reusable.
Currently, most of the UI form logic is situated in the
*Form
classes associated with each quest. This makes the code not really reusable because other quests may need other answer options or answer type, want a different style, different pictures etc etc.Inheritance
The first solution (and in code: the oldest solution) that comes to mind for code reuse is to use inheritance. Examples of this approach are
AImageListQuestAnswerFragment
,AListQuestAnswerFragment
or the newAStreetSideSelectFragment
.*Form
classes already inherit fromAbstractQuestAnswerFragment
, the UI code is only reusable for other quest answer formsCompound Views
So another solution could be to encapsulate the view logic into custom (compound) views. Examples of this approach are
StreetSideSelectPuzzle
,LanesSelectPuzzle
,AutoCorrectAbbreviationsEditText
orLengthInput
. This is better than the inheritance approach becauseTimeInput
class that allows to input a time and theTimeRangeInput
class would be just a view that consists of twoTimeInput
and some extra logic. TheTimeRangeInput
itself could then be part of another view, e.g.OpeningHoursView
But I found that this, too, has some issues. Minor issues:
View
that is used as the view's parent. This exposes a lot of functionality unintentionally that may break the internal logic of the custom view. E.g.AutoCorrectAbbreviationsEditText
inherits fromEditText
and internally registers aOnEditorActionListener
to do stuff. Now, anEditText
only allows oneOnEditorActionListener
at a time and the method to set it is public, so a user of this class could break some functionality by re-setting that listener.However, like a
Fragment
, aView(Group)
does not only manage the view but also creates and contains the view it manages:LengthInput
allows to input a length in meters or feet+inches. It is however currently only used for the AR Measure quests and not for theAddMaxHeight
quest because the input in the latter has a different styling and arrangement of the involved viewsViewController
So, to deal with the mentioned shortcomings, we could have a class that is not a View itself, does not contain or create the view, but just manages it. E.g. a
LengthInputViewController
would look pretty much the same as the currentLengthInput
class with all its interface, except that the view(s) it should manage are passed in at the constructor.So, the view can be injected by the containing custom view or containing fragment and it can be styled and arranged differently, the
*ViewController
does not care. I.e.,LengthInput
could still exist but the only thing it would do is to create the (default) view and delegate everything else toLengthInputViewController
.This solves most of the remaining issues with custom views. So, it seems kind of obvious that this pattern is desirable for reusing UI logic independent of styling.
I am lacking really good naming for it though. Other candidates for names are/were:
*ViewController
because it controls view(s). The name is used in iOS programming for something that would be very similar to aFragment
orActivity
on Android. So, not perfect. But on Android, this name is not used for anything.*ViewManager
because it manages view(s). But manager, to me, sounds like something bigger.*Widget
. The name is used for those apps you have on your home screen, howeverAlso, I didn't find any source that wrote about this pattern. So, I am kind of unsure if I maybe forgot to consider something. What's your take on this?
(FYI in MVC, MVP and MVVM, all of this here is clearly still 100% in the View layer)
Beta Was this translation helpful? Give feedback.
All reactions