Custom Layouts : Design and Utilization (Part III : Development )

Saurabh Pant
3 min readJun 17, 2017

Development is not coding, it is creativity

When it comes to display symbols, icons and static images, we generally use png/jpeg files. These files take memory, increase the apk size and also affect the speed of execution.

In this project we’re using Typeface font files mainly FontAwesome. This is very small sized file which contains symbols and we can use them as text in our layouts directly. Their color and size can be changed
at run time. Their execution is very fast. Hence making our app light and fast.

For how to use the FontAwesome, check this post.

Now, whenever we create a custom layout, we always must know which type of input and outputs this layout would deliver. Let’s consider our LoginButton layout.

public class LoginButton extends LinearLayout {

@BindView(R.id.login_button_loader)ProgressBar login_loader;
@BindView(R.id.login_button_text)AppTextViewRegular login_text;

private Context context;

public LoginButton(Context context) {
super(context);
this.context = context;
createView();
}

public LoginButton(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
createView();
}

private void createView(){
inflate(context, R.layout.ly_login_button, this);
ButterKnife.bind(this);
setOrientation(LinearLayout.HORIZONTAL);
setBackgroundResource(R.drawable.bg_round_corners);
setGravity(Gravity.CENTER | Gravity.CENTER_VERTICAL);
setButtonText("Login");
login_loader.getIndeterminateDrawable().setColorFilter(0xFFFFFFFF, android.graphics.PorterDuff.Mode.MULTIPLY);
setButtonLoadingState(false);
}

public void setButtonText(String text){
login_text.setText(text);
}

public void setButtonLoadingState(boolean state){
ViewHelper.setViewVisibility(login_loader, state);
}
}

As we can see, setButtonText() and setButtonLoadingState() are two methods that our calling activity/fragment would be using. We knew that we might have to set text on the button and have to maintain the button loading state and so we defined these two. You can create more as per your need.

Finally, our main activity layout ac_login.xml would look like something as

<LinearLayout
android:id="@+id/login_field_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_weight="1"
android:animateLayoutChanges="true"
android:gravity="center"
android:orientation="vertical"
>

<com.aqua.demoproject.ui.views.LoginField
android:id="@+id/login_email"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="center"
login_field:has_focus="true"
login_field:hint_text="email"
login_field:icon_code="@string/icon_email"
/>

<com.aqua.demoproject.ui.views.LoginField
android:id="@+id/login_password"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="center"
android:layout_marginTop="10dp"
login_field:has_focus="false"
login_field:hint_text="password"
login_field:icon_code="@string/icon_password"
login_field:is_password="true"
/>

<com.aqua.demoproject.ui.views.LoginField
android:id="@+id/login_confirm_password"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_gravity="center"
android:layout_marginTop="10dp"
login_field:has_focus="false"
login_field:hint_text="confirm password"
login_field:icon_code="@string/icon_lock"
/>

</LinearLayout>

<com.aqua.demoproject.ui.views.LoginButton
android:id="@+id/login_button"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_centerHorizontal="true"
android:layout_marginBottom="5dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
/>

Now, we have all our custom views in our main xml. We can see how much less code we have to write now as compared to if we’d have written all views directly in here. We clearly defined what views are actually doing what.

In MainActivity.java , we’ll access these views like normal views. By using Butterknife, all view bindings become only a one liner task.

@BindView(R.id.login_email)LoginField login_email;
@BindView(R.id.login_password)LoginField login_password;
@BindView(R.id.login_confirm_password)LoginField confirm_password;
@BindView(R.id.login_button)LoginButton login_button;
@BindView(R.id.login_field_layout)LinearLayout login_field_layout;

This helps developer to keep the focus on the main fields only and not on the view coding. All these custom fields have helper methods defined in their own classes which we require. E.g.

login_button.setButtonLoadingState(true);
login_email.enableField(false);
login_password.enableField(false);
login_password.setError();
if (!login_email.getFieldText().isEmpty()) {
if (!login_password.getFieldText().isEmpty()) { ...

So, this is the benefit of creating custom layouts.

With advantages come disadvantages.

Using custom layouts also requires a very large set of classes to handle and maintain. Developer needs to document which section is doing what and how. Sometimes view hierarchy becomes so deep that it becomes difficult to maintain.

So depending on the app and your requirement, you can follow them. But it is beneficial to use them. I use them to keep my code a bit less complicated.

Hope, this series would help you in development. Will keep posting such series.

Cheers :)

--

--

Saurabh Pant

App Developer (Native & Flutter) | Mentor | Writer | Youtuber @_zaqua | Traveller | Content Author & Course Instructor @Droidcon | Frontend Lead @MahilaMoney