Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/evant/holdr
[Deprecated] Because typing findViewById() in Android is such a pain.
https://github.com/evant/holdr
Last synced: about 1 month ago
JSON representation
[Deprecated] Because typing findViewById() in Android is such a pain.
- Host: GitHub
- URL: https://github.com/evant/holdr
- Owner: evant
- License: apache-2.0
- Created: 2014-07-27T21:24:18.000Z (over 10 years ago)
- Default Branch: main
- Last Pushed: 2020-06-14T22:58:16.000Z (over 4 years ago)
- Last Synced: 2023-11-07T15:36:55.137Z (about 1 year ago)
- Language: Java
- Homepage:
- Size: 1.89 MB
- Stars: 208
- Watchers: 15
- Forks: 10
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
## [Deprecated]
[View Binding](https://developer.android.com/topic/libraries/view-binding) does everything holdr does but is a first-party solution. I will still be maintaing this project and fixing any bugs, but I will not be adding any new features.Holdr
======## What is Holdr?
Holdr generates classes based on your layouts to help you interact with them in
a type-safe way. It removes the boilerplate of doing
`TextView myTextView = findViewById(R.id.my_text_view)` all the time.## Doesn't [Butter Knife](http://jakewharton.github.io/butterknife/)/[AndroidAnnotaions](http://androidannotations.org/)/[RoboGuice](https://github.com/roboguice/roboguice) already do that?
This is a different approach to solving the same problem, the important
difference is your layout dictates what is generated instead of annotations on
your classes. This means that it's much less likely for your code and layouts to
get out of sync.This approach also means zero reflection (and no proguard issues) and works
equally as well in library projects.## Usage
Simply apply the gradle plugin and your done!
```groovy
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0'
classpath 'me.tatarka.holdr:gradle-plugin:1.5.2'
}
}repositories {
mavenCentral()
}apply plugin: 'com.android.application'
apply plugin: 'me.tatarka.holdr'
```
alternativly, you can use the new gradle 2.1+ syntax
```groovy
plugins {
id "me.tatarka.holdr" version "1.5.2"
}
```Say you have a layout file `hand.xml`.
```xml
```
Holdr will create a class for you named `your.application.id.holdr.Holdr_Hand`.
This class is basically a view holder that you can instantiate anywhere you have
a view.### In an Activity
```java
public class MyActivity extends Activity {
private Holdr_Hand holdr;@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.hand);
holdr = new Holdr_Hand(findViewById(android.R.id.content));
holdr.text.setText("Hello, Holdr!");
}
}
```### In a Fragment
```java
public class MyFragment extends Fragment {
private Holdr_Hand holdr;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.hand, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
holdr = new Holdr_Hand(view);
holdr.text.setText("Hello, Holdr!");
}
@Override
public void onDestroyView() {
super.onDestroyView();
holdr = null;
}
}
```### In an Adapter
```java
public class MyAdapter extends BaseAdapter {
// other methods
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Holdr_Hand holdr;
if (convertView == null) {
holdr = new Holdr_Hand(inflater.inflate(R.layout.hand, parent, false));
holdr.getView().setTag(holdr);
} else {
holdr = (Holdr_Hand) convertView.getTag();
}
holdr.text.setText(getItem(position));
return holdr.getView();
}
}
```### In a Custom View
```java
public class MyCustomView extends LinearLayout {
Holdr_Hand holdr;
// other methods
private void init() {
holdr = new Holdr_Hand(inflate(getContext(), R.layout.hand, this));
holdr.text.setText("Hello, Holdr!");
}
}
```### Multiple layouts
You may have multiple instances of a layout (in `layout` and `layout-land` for
example). In that case Holdr will merge the id's across them. If an id appears
in one and not the other, a `@Nullable` annotation will be generated to warn you
of this.If the type of the view doesn't match, Holdr will take the most
conservative route and use type `View`. If instead, they share a common
superclass and you want to use that, you can use the `app:holdr_class` to
override the view type so that they match.```xml
```
### Callback Listeners
You can also specify listeners for your Activity/Fragment/Whatever to handle
to make working with callbacks a bit nicer. For example, if you had the layout
file `hand.xml`,```xml
```
The generated `Holdr_Hand` class will also have a listener interface for you to
implement.```java
public class MyActivity extends Activity implements Holdr_Hand.Listener {
private Holdr_Hand holdr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.hand);
holdr = new Holdr_Hand(findViewById(android.R.id.content));
holdr.setListener(this);
}
@Override
public void onMyButtonClick(Button myButton) {
// Handle button click.
}
}
```Here is a list of all the listeners you can handle:
- `holdr_onTouch`
- `holdr_onClick`
- `holdr_onLongClick`
- `holdr_onFocusChange`
- `holdr_onCheckedChanged`
- `holdr_onEditorAction`
- `holdr_onItemClick`
- `holdr_onItemLongClick`You can also specify a custom method name by doing
`app:holdr_onClick="myCustomMethodName"` instead. You can also specify the same
name on multiple views and they will share a listener (provided the listeners
are of the same type).### Custom Superclass
Want to use a `Holdr` in a place where you need a specific subclass?
(`RecyclerView.ViewHolder` for example). Just use the attribute
`app:holdr_superclass="com.example.MySuperclass` and it will subclass that
instead of `Holdr`. The only requirement is that the superclass must contain a
constructor that takes a `View`.### Controlling What's Generated
If you don't like the idea of a whole bunch of code being generated for all your
layouts (It's really not much, I promise!), you can add `holdr.defaultInclude
false` to your `build.gradle` and then you can manually opt-in for each of your
layouts.The easiest way to opt-in is to add `app:holdr_include="all"` to the root
view of that layout.By default, every view with an id gets added to the generated class. You can use
the attributes `holdr_include` and `holdr_ignore` to get more granular
control. Both take either the value `"view"` to act on just the view it's used
on or `"all"` to act on that view and all it's children. For example,```xml
`
```
would include only `text1` in the generated class.
Note: The current implementation only allows you to nest these attributes 2
levels deep (ignore inside include inside ignore won't work). I don't think
there is a use case complex enough to warrant this, but it may be fixed in a
later version if there is a need.Finally, if you don't like the field name generated for a specific id, you can
set it yourself by using `app:holdr_field_name="myBetterFieldName"` on a view.### Android Studio Plugin
Tired of having to build your project after every layout change? With the intellij plugin the Holdr classes will be auto-generated as soon as you save!
Go to `Settings -> Plugins -> Browse Repositories...` and search for "Holdr".
The plugin will also allow you to do a refactor-rename on holdr fields and use goto-source (Ctrl-click or Ctrl-B) to go directly to the view in the layout.
(Requires Android Studio `0.6.0+` or Intellij 14)
If instead you feel like living on the edge, you can build install the plugin manually.
1. Clone the repo
2. Change `studio.path` in `gradle.properties` to point to your Android Studio/Intellij instalation directory
3. Run `./gradlew intellij-plugin:build --configure-on-demand`
4. Go to `Settings -> Plugins -> Install plugin from disk...` and install the jar in `./intellij-plugin/build/libs/`