Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    robinchew
    @robinchew
    Hi everyone, I'm new to Android development, but familiar with web frontend development using Mithril. When I read up on fragments since it is the blessed way of doing Android dev, I was scared into searching for alternatives. I searched for 'android virtual dom' and I was pleased to find someone @zserge being inspired by mithril, resulting with Anvil.
    One of the killer features of mithril over react, is that I can easily fallback to my dirty ways of jquery dom manipulation post render.
    Mithril really doesn't get in the way, and works well with others. So I wonder if Anvil has this level of flexibility? Can I get fragments (if I understood how to work it) to work together with Anvil?
    Oh by the way is this where the Anvil community largely hang?
    Serge Zaitsev
    @zserge
    Hi Robin! Thanks for your interest in Anvil (and Mithril, too - I think it's a very underrated framework)
    You're right, Anvil often plays well with normal Android development approach - you can use it with fragments, you can use View instances and call their methods directly if you want. Also, you can use XMLs if you prefer that to Anvil's DSL (or if you're refactoring existing code).
    As for the Anvil's community - there's not much of a community that I'm aware of. There are some very nice and helpful people who hanged out here and helped me to do a big refactoring last year, but as long as everything is working - people just use it, eventually filing issues on github. So if you have a question - feel free to ask it here, if you found a bug - submit it on github.
    robinchew
    @robinchew
    So I can mess with the element after the virtualdom has rendered it? For example in mithril:
    m('div', { oncreate: function(vdom){
        vdom.element.innerHTML = 'I am Replacing Div Content!';
    }}, 'Div Content')
    Excuse my excessive edits
    robinchew
    @robinchew
    Cool with the community, let the code speak for itself.
    Serge Zaitsev
    @zserge
    Exactly. To avoid confusion I have to mention that Anvil has evolved from "virtual DOM" concept to the "incremental DOM", because virtual DOM turned out to be too heavy for Android's GC.
    However the general logic is still the same - during the rendering cycle current "declarative" layout is compared to the real layout and the real layout is lazily patched according to the changes.
    You should be able to get an instance of a View like this:
    public void view() {
      linearLayout(() -> {
        button(() -> { // Inside any view block...
          init(() -> { // you may declare "init" function and pass lambda into it
            Button b = Anvil.currentView(); // Type of a view is deduced automatically in most cases
            mButton = (Button) Anvil.currentView(); // Or you may cast it explicitly
            // You are not forced to do this within "init" block, but otherwise your code will be called on every rendering cycle
          })
        });
      });
    }
    // later on you may use mButton as a normal view:
    mButton.performClick();
    As an alternative, you may use View IDs:
    button(() -> {
      id(MY_BUTTON);
    });
    // later just find view by ID, IIRC Android caches views and their IDs:
    findViewByID(MY_BUTTON).performClick();
    robinchew
    @robinchew
    Thanks for the code example.
    robinchew
    @robinchew
    I notice that mithril nests the elements via the arguments, but anvil nests via lambdas. m() will return nested plain objects, does linearLayout() return anything?
    Serge Zaitsev
    @zserge

    No, in Anvil there are two forms of DSL:
    One is for Java 8 and Kotlin, where you pass lambdas. Here functions return void.
    Another is for Java 6 and it uses a trick which makes it look similar to Mithril:

    o (linearLayout(),
       size(FILL, FILL),
       o (button(),
          size(FILL, WRAP),
          onClick(someHandler)),
       o (button(),
          size(FILL, WRAP),
          text(someText),
          onClick(someOtherHandler)));

    o in this case looks like a bullet point in the list, so the whole layout (if nicely indented) looks like a tree of view items.
    In this case to tell views from attributes in the function parameters some functions return some special types to make the compiler check for the types. But again, they don't return actual views. The only way to get a view instance is to use Anvil.currentView(). Good news is that you can use it anywhere in you code (e.g. in other methods), as long as your code is called from within the view() function.

    robinchew
    @robinchew
    Does the o DSL pass lambdas behind the scenes anyway?
    Is it just your personal design choice to pass lambdas, or was it something that forces a need to be lambdas?
    robinchew
    @robinchew
    @zserge I'm writing some anvil now, and I need to do constraints, and I'm not sure what's the Anvil way of dealing with constraints. Nothing much on Google on it.
    robinchew
    @robinchew

    This is what I attempted:

    class HelloView(c: Context, constraint: ConstraintLayout) : RenderableView(c) {
        val constraint: ConstraintLayout
        init {
            this.constraint = constraint
        }
        override fun view() {
            textView {
                text(R.string.login_title)
                val title: TextView = Anvil.currentView()
                this.constraint.addView(title)
            }
        }
    }
    
    class LoginActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            val constraint = ConstraintLayout(this)
    
            setContentView(HelloView(this, constraint))
        }
    }

    However that will error saying, java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() which I understand.

    It's kotlin by the way
    Also my example didn't append constraint to anything
    robinchew
    @robinchew
    I need to get constraints to work programmatically first, which is already quite painful
    robinchew
    @robinchew
    Without using Anvil, I can't even do a simple top margin constraint on a TextView. If I have to resort to XML for constraints then it defeats the purpose of Anvil I think. But I would like to know your opinion on constraints.
    robinchew
    @robinchew
    Anyway I got something simple working:
    class ContactView(c: Context) : RenderableView(c) {
        override fun view() {
            textView {
                text("Contact Title")
            }
        }
    }
    
    class LoginActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            val constraintLayout = ConstraintLayout(this)
            constraintLayout.id = 1
            setContentView(constraintLayout)
    
            val contactUs = ContactView(this)
            val clpcontactUs = ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT)
    
            constraintLayout.addView(contactUs)
    
            val constraintSet = ConstraintSet()
            constraintSet.clone(constraintLayout)
            constraintSet.constrainWidth(contactUs.id, ConstraintSet.WRAP_CONTENT)
            constraintSet.centerHorizontally(contactUs.id, constraintLayout.id)
            constraintSet.connect(contactUs.id, ConstraintSet.TOP, constraintLayout.id, ConstraintSet.TOP, 68)
            constraintSet.applyTo(constraintLayout)
    And there's a bug if you use ConstraintSet.LEFT, it doesn't work, but apparently does in XML. https://issuetracker.google.com/issues/62154545
    robinchew
    @robinchew
    Sooo what's the state of the Anvil project?
    robinchew
    @robinchew