Code Monkey home page Code Monkey logo

renderers's Introduction

Renderers Build Status Maven Central

Renderers is an Android library created to avoid all the RecyclerView/Adapter boilerplate needed to create a list/grid of data in your app and all the spaghetti code that developers used to create following the ViewHolder classic implementation. As performance is also important for us, we've added a new diffUpdate and a RVListRendererAdapter method supporting differential updated transparently in the main thread and a background thred respectively.

With this library you can improve your RecyclerView/Adapter/ViewHolder code. The one sometimes we copy and paste again and again 😃. Using this library you won't need to create any new class extending from RecyclerViewAdapter.

Create your Renderer classes and declare the mapping between the object to render and the Renderer. The Renderer will use the model information to draw your user interface. You can reuse them in all your RecyclerView and ListView implementations easily. That's it!

Screenshots

Demo Screenshot

Usage

To use Renderers Android library you only have to follow three steps:

    1. Create your Renderer class or classes extending Renderer<T>. Inside your Renderer classes. You will have to implement some methods to inflate the layout you want to render and implement the rendering algorithm.
public class VideoRenderer extends Renderer<Video> {

       @BindView(R.id.iv_thumbnail)
       ImageView thumbnail;
       @BindView(R.id.tv_title)
       TextView title;
       @BindView(R.id.iv_marker)
       ImageView marker;
       @BindView(R.id.tv_label)
       TextView label;

       @Override
       protected View inflate(LayoutInflater inflater, ViewGroup parent) {
           View inflatedView = inflater.inflate(R.layout.video_renderer, parent, false);
           ButterKnife.bind(this, inflatedView);
           return inflatedView;
       }

       @Override
       protected void render() {
           Video video = getContent();
           renderThumbnail(video);
           renderTitle(video);
           renderMarker(video);
           renderLabel();
       }

       @OnClick(R.id.iv_thumbnail)
       void onVideoClicked() {
           Video video = getContent();
           Log.d("Renderer", "Clicked: " + video.getTitle());
       }

       private void renderThumbnail(Video video) {
           Picasso.with(context).load(video.getResourceThumbnail()).placeholder(R.drawable.placeholder).into(thumbnail);
       }

       private void renderTitle(Video video) {
           this.title.setText(video.getTitle());
       }
}

You can use Jake Wharton's Butterknife library to avoid findViewById calls inside your Renderers if you want. But the usage of third party libraries is not mandatory.

    1. If you have just one type of item in your list, instantiate a RendererBuilder with a Renderer instance and you are ready to go:
Renderer<Video> renderer = new LikeVideoRenderer();
RendererBuilder<Video> rendererBuilder = new RendererBuilder<Video>(renderer);

If you need to render different objects into your list/grid you can use RendererBuilder.bind fluent API and that's it:

RendererBuilder<Video> rendererBuilder = new RendererBuilder<Video>()
         .bind(VideoHeader.class, new VideoHeaderRenderer())
         .bind(Video.class, new LikeVideoRenderer());
    1. Initialize your ListView or RecyclerView with your RendererBuilder and an optional List inside your Activity or Fragment. You should provide a list of items to configure your RendererAdapter or RVRendererAdapter.
private void initListView() {
    adapter = new RendererAdapter<Video>(rendererBuilder, list);
    listView.setAdapter(adapter);
}

or

private void initListView() {
    adapter = new RVRendererAdapter<Video>(rendererBuilder, list);
    recyclerView.setAdapter(adapter);
}

Remember, if you are going to use RecyclerView instead of ListView you'll have to use RVRendererAdapter instead of RendererAdapter.

    1. Diff updates:

If the RecyclerView performance is crucial in your application remember you can use diffUpdate method in your RVRendererAdapter instance to update just the items changed in your adapter and not the whole list/grid.*

adapter.diffUpdate(newList)

This method provides a ready to use diff update for our adapter based on the implementation of the standard equals and hashCode methods from the Object Java class. The classes associated to your renderers will have to implement equals and hashCode methods properly. Your hashCode implementation can be based on the item ID if you have one. You can use your hashCode implementation as an identifier of the object you want to represent graphically. We know this implementation is not perfect, but is the best we can do wihtout adding a new interface you have to implement to the library breaking all your existing code. Here you can review the DiffUtil.Callback implementation used in this library. If you can't follow this implementation you can always use a different approach combined with your already implemented renderers.

Also, RVListRendererAdapter provides a way to perform diff updates in a background thread transparently. When using RVListRendererAdapter you'll have a default DiffUtil.ItemCallback implementation (https://developer.android.com/reference/android/support/v7/util/DiffUtil.ItemCallback)) based on referencial equality for areItemsTheSame method and structural equality for areContentsTheSame method. You also have constructors on this class to provide your own implementation for DiffUtil.ItemCallback. You can even configure the threads used to perform the calculations through AsynDifferConfig class (https://developer.android.com/reference/android/support/v7/recyclerview/extensions/AsyncDifferConfig).

This library can also be used to show views inside a ViewPager. Take a look at VPRendererAdapter 😃

Usage

Add this dependency to your build.gradle:

dependencies{
    implementation 'com.github.pedrovgs:renderers:4.1.0'
}

Complex binding

If your renderers binding is complex and it's not based on different classes but in properties of these classes, you can also extend RendererBuilder and override getPrototypeClass to customize your binding as follows:

public class VideoRendererBuilder extends RendererBuilder<Video> {

  public VideoRendererBuilder() {
    List<Renderer<Video>> prototypes = getVideoRendererPrototypes();
    setPrototypes(prototypes);
  }

  /**
   * Method to declare Video-VideoRenderer mapping.
   * Favorite videos will be rendered using FavoriteVideoRenderer.
   * Live videos will be rendered using LiveVideoRenderer.
   * Liked videos will be rendered using LikeVideoRenderer.
   *
   * @param content used to map object-renderers.
   * @return VideoRenderer subtype class.
   */
  @Override
  protected Class getPrototypeClass(Video content) {
    Class prototypeClass;
    if (content.isFavorite()) {
      prototypeClass = FavoriteVideoRenderer.class;
    } else if (content.isLive()) {
      prototypeClass = LiveVideoRenderer.class;
    } else {
      prototypeClass = LikeVideoRenderer.class;
    }
    return prototypeClass;
  }

  /**
   * Create a list of prototypes to configure RendererBuilder.
   * The list of Renderer<Video> that contains all the possible renderers that our RendererBuilder
   * is going to use.
   *
   * @return Renderer<Video> prototypes for RendererBuilder.
   */
  private List<Renderer<Video>> getVideoRendererPrototypes() {
    List<Renderer<Video>> prototypes = new LinkedList<Renderer<Video>>();
    LikeVideoRenderer likeVideoRenderer = new LikeVideoRenderer();
    prototypes.add(likeVideoRenderer);

    FavoriteVideoRenderer favoriteVideoRenderer = new FavoriteVideoRenderer();
    prototypes.add(favoriteVideoRenderer);

    LiveVideoRenderer liveVideoRenderer = new LiveVideoRenderer();
    prototypes.add(liveVideoRenderer);

    return prototypes;
  }
}

References

You can find implementation details in these talks:

Software Design Patterns on Android Video

Software Design Patterns on Android Slides

Developed By

Follow me on Twitter Add me to Linkedin

License

Copyright 2016 Pedro Vicente Gómez Sánchez

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.

renderers's People

Contributors

firezenk avatar flipper83 avatar jcminarro avatar lukard avatar marcbenedi avatar pedrovgs avatar raycoarana avatar roshakorost avatar serchinastico avatar silviorp avatar stefma avatar taher-ghaleb avatar tonilopezmr avatar vjgarciag96 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

renderers's Issues

Items groups separator list

Hi Pedro,

I have a list items sorted and grouped by type. Is possible render this list with separators between groups of items?

I've done many tests but I've not achieved :_(
I tried to return in the method inflate() two different views depending on some PanelItemViewModel parameter but when I call getContent() method always return null.

CurrentDistributionPanelItemViewModel

public class CurrentDistributionPanelItemViewModel {

    private final WorkOrderLineViewModel workOrderLine;
    private final CurrentDistributionPanelSeparatorViewModel separator;

    public CurrentDistributionPanelItemViewModel(WorkOrderLineViewModel workOrderLine,
                                                 CurrentDistributionPanelSeparatorViewModel separator) {
        this.workOrderLine = workOrderLine;
        this.separator = separator;
    }

    public boolean isSeparator() {
        if(separator != null) {
            return true;
        }
        return false;
    }

    public WorkOrderLineViewModel getWorkOrderLine() {
        return workOrderLine;
    }

    public CurrentDistributionPanelSeparatorViewModel getSeparator() {
        return separator;
    }
}

CurrentDistributionPanelItemRenderer.java

...

@Override
    protected View inflate(LayoutInflater inflater, ViewGroup parent) {
        View v = null;
        if(getContent().getWorkOrderLine() == null) {
        }
        else {
            v = inflater.inflate(R.layout.work_order_line, parent, false);
            resource = (TextView) v.findViewById(R.id.resource);
            costGroup = (TextView) v.findViewById(R.id.cost_group);
            unitsLabel = (TextView) v.findViewById(R.id.units_label);
            unitsValue = (TextView) v.findViewById(R.id.units_value);
        }
        return v;
    }

How can I achieve it?

Thanks

Improve Kotlin support

We are going to update all the project documentation and add a new module supporting Kotlin properly. We will make the library more idiomatic and kotlin friendly so our Android users can enjoy it 😃

Ejemplo más sencillo

Puedes subir algún ejemplo un poco más sencillo y directo?

Me está costando un poco implementar la librería en mi proyecto. Me he liado un poco con el ejemplo que tienes subido.

Sobre todo a la hora de iniciar el adaptador:

RendererAdapter adapter = new RendererAdapter(inflater,B, C);

En B que incluyo? y en C?

Gracias.

Listener de click a elemento de la lista

Buenas Pedro, no consigo entender como implementar la gestion del click a un elemento de la lista sin hacer uso de inyeccion de dependencias..¿Tienes algun ejemplo?
Gracias por la libreria, creo que me va a ahorrar años de dolores de cabeza xD

Add support for PagedListAdapter

After the latest Architecture Components release made by Google during December 2017 we've noticed they have released a new adapter named PagedListAdapter we should support. As the architecture component is a new module we should provide this as a new renderers module so we don't add the architecture components to the main artifact. More information can be found in this video

Missing methods implementation in readme file

Following the instructions on the libary's readme file the app wont compile due to the following errors:

  • Class 'VideRenderer' must either be declared abstract or implement abstract method setupView(View) in Renderer
  • Class 'VideRenderer' must either be declared abstract or implement abstract method hookListeners(View) in Renderer

So it looks like the library have been changed but the example has not been updated we the new needed code

Update dependencies

It's time to review our build.gradle configuration and update some dependencies 😃

Simplify renderer abstraction

Method Renderer::hookListeners declared abstract, but there could be instances that do not require registering any callbacks at all.

Support for LayoutContainer

As it turns out, Kotlin synthetic properties cache works by default on Activities, Fragments, and Views, but it does not do so for ViewHolder. They fixed this as of Kotlin 1.1.4 via LayoutContainer.

Consumers of this libraries have to make sure they make their Renderers implement LayoutContainer if they are using synthetic properties inside of them. If they do not, their ViewHolders are going to call findViewById() on every call to render() making their ViewHolders obsolete. It would be nice if the library itself did this maybe by adding a Kotlin specific artifact that implements this interface (implementation should be trivial). Thoughts?

Do abstract content types work?

I am trying to use it for the first time and I am following your sample implementation. My implementation varies where you have a concrete Video class, I have an abstract class. I had no problem implementing the various Renderer classes to handle my different content types but when I went to implement my RendererBuilder, I am unable to add my concrete Renderer classes to the list. This may be something stupid I am doing with my generic typing but beating my head on my desk is getting me nowhere. Thought I'd ask if you could shed some light on it. Thanks for sharing your library. I am really looking forward to using it.

server loading imitation

Hello thx you for good project but i have manny questions.. First sorry about my English but i hope you understand me ) I try write simple project with Renderes lib, for server loading imitation i use handler .. Some think like this

new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                RandomVideoCollectionGenerator randomVideoCollectionGenerator =
                        new RandomVideoCollectionGenerator();
                adapter.addAll(randomVideoCollectionGenerator.generate(4));
            }
        }, 5000);

But lib don't add this items to recyclerView.. i don't understand why... can you say me?

In my production code i use ItemAnimator.. is it ok for Renderes lib? how i can write custom method like this -

public void updateItems(List<String> data, boolean animated) {
        feedItems.clear();
        feedItems.addAll(data);
        if (animated) {
            notifyItemRangeInserted(0, feedItems.size());
        } else {
            notifyDataSetChanged();
        }
    }

i think i can override RVRendererAdapter and write what i need but i don't shore ..

Thx for your time!

What about recyclerView multiselect?

Hello:

  With listview i can do multiselect and start Action Mode easy.

  With recyclerView it is more complicated, maybe you can include an extension to recyclerView that include multiselect and works with this library or my best chance will be still using ListView?

Thanks,

Improve RendererBuilder API.

RendererBuilder classes responsibility is related to map objects to render with Renderer instances. We should improve how RendererBuilder is used and a good approach could be offer a map(ClassToRender.class,Renderer) method to avoid use RendererBuilder by extension. The goal: simplify how RendererBuilder is used.

RxJaxa

Nice, how would you integrate the Observable pattern in your library?

Add support to use Renderers with just one Renderer in a easy way.

Use Renderers when you need just one Renderer to draw your lists can be a little bit complicated. You have to create a RendererBuilder with just one Renderer instance as prototype and we can do it better. The goal: simplify how this library can be used for the simplest example.

IOS Version

Hi Pedro, thanks for sharing such a great library. Is there an IOS version of this library or any plan to make one?

No way to bind several model classes using RendererBuilder.bind

In rendererBuilder there are 2 methods, that have wired signature.

public RendererBuilder<T> bind(Class<T> clazz, Renderer<T> prototype)
public RendererBuilder<T> bind(Class<T> clazz, Class<? extends Renderer> prototypeClass)

This signature doesn't allow to bind model classes that extends to T to some prototype.
For example in case when we have class A and class B, where B extends A, if we create RendererBuilder<A> we can only bind class A to some prototype. There is no way to bind class B, because Class<B> doesn't extends Class<A>.

I suggests to change signature of these methods to

public <G extends T> RendererBuilder<T> bind(Class<G> clazz, Renderer<G> prototype)
public <G extends T> RendererBuilder<T> bind(Class<G> clazz, Class<? extends Renderer> prototypeClass)

This would allow to bind deferent subclasses of T to renderers.

Create Sample for new Generic Functionality

Hello,

I have started work on new sample, that binds different renderer classes to different model classes, was planing to make it on top of Video and VideoRenderer. But there are problems:
VideoRenderer sets layout that will use in subclasses,
Video model has too much fields.

What if I would make completely different example, not about videos?

Making use of Collection instead of AdapteeCollection

Hi everyone!

I would like to know if we could change RVRendererAdapter and RVListRendererAdapter collection type to Collection<T> instead of AdapteeCollection<T>.

It causes me trouble in the following situation. I would like to update just one item from the list instead of performing a full diffUpdate. Since there is no set method in AdapteeCollection I can only do the following:

List<T> list = (List<T>) collection;
list.set(position, newElement);
notifyItemChanged(position);

The drawback of this approach is that it is performing a cast over collection assuming that the implementation inherits from List.

Another way of tackling this issue would be copying all elements into aList<T> and performing the set operation there. But that is even worse given the original collection is already a List<T> and we would be doing a useless copy.

Are there any arguments against using Collection instead of AdapteeCollection?

Some permissions are added to APK

I detected this behaviour just after add your library.

android:uses-permission#android.permission.READ_PHONE_STATE
IMPLIED from AndroidManifest.xml:2:1 reason: com.pedrogomez.renderers has a targetSdkVersion < 4
android:uses-permission#android.permission.READ_EXTERNAL_STORAGE
IMPLIED from AndroidManifest.xml:2:1 reason: com.pedrogomez.renderers requested WRITE_EXTERNAL_STORAGE

Problema al borrar un item

Buenas pedro mi nombre es luis, he estado usando tu libreria y la verdad es que me parece muy buena por lo que te felicito, estudie informatica en la um igual que tu y te he visto por ai... bueno queria preguntarte como puedo eliminar un item de mi lista usando tu libreria porque una de las pegas que encuentro es que no tengo acceso al adaptador por lo que me resulta dificil hacer algunas cosas con mi lista...espero tu respuesta gracias y de nuevo enhorabuena por tu libreria esta muy bien hecha....

RVRendererAdapter.addAll doesn't respect Collection.addAll signature

RVRendererAdapter addAll signature differs from the Collection one making it impossible to use it with collections of subtypes.
The fix is as easy as changing the method signature from

public void addAll(Collection<T> elements)

to

public void addAll(Collection<? extends T> elements)

It will be backwards compatible which is always nice.

Implementing RendererAdapter.isEnabled(int position)

I am thinking about adding methods isEnabled(int position) and areAllItemsEnabled() to the RendererAdapter, so it would be possible to disable some items.

However RendererAdapter doesn't know much about collection of items that it handles, so I feel like it should call method isEnabled(T content) in the mapped Renderer.

What do you think about this functionality?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.