Introduction
In this article, we are going to learn how to build custom tabs with animation backward and forward. For example, there are 5 tabs, and by default 0th position tab is selected if we select the 4th position tab, then the tab's background(so-called Highlighter View) will travel forward with animation. The same case is with backward selection highlighter view will travel backward direction.
The animation we will use is translated animation, which will be on a view. The animation used is a translation of views.
There are two ways. Firstly, we can use Tablayout. Secondly, we can create custom tabs like we are going to do.
Step 1. Create a sample project with an empty activity called MainActivity.java, and the default XML will be generated as the so-called layout file associated with the main activity.
Step 2. Create a widget custom tabs widget so we can embed it into any project. We are creating a generic widget that can be reused across the same project.
Name that file HorizontalTabBar.java. It is basically a layout file or a custom view that extends FrameLayout.
package com.example.myapplication;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class HorizontalTabBar extends FrameLayout {
private Context context;
private List<String> contentList = new ArrayList<>();
LinearLayout linearLayout;
private OnSlideTabClickListener onSlideTabClickListener;
int selectedIndex;
LinearLayout highLighterView;
int parentHeight = 65;
int childHeight = 55;
LinearLayout textLayout;
int width = 384;
public HorizontalTabBar(@NonNull Context context) {
super(context);
this.context = context;
}
public HorizontalTabBar(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
public void populateSliderData(List<String> sliderData, int selectedIndex,
OnSlideTabClickListener onSlideTabClickListener) {
this.onSlideTabClickListener = onSlideTabClickListener;
removeAllViews();
contentList.clear();
contentList = sliderData;
this.selectedIndex = selectedIndex;
init();
setSelectedIndex(selectedIndex);
}
/** create containers to accommodate textviews **/
private void init() {
linearLayout = new LinearLayout(context);
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, parentHeight);
linearLayout.setLayoutParams(layoutParams);
if (!contentList.isEmpty()) {
width = getScreenWidth(context) / contentList.size();
}
addView(linearLayout);
buildBackgroundView(width);
buildHighlighterView(width);
buildTextContent(width);
}
/** create background view that can hold the highlighter
* @param width
* * ***/
private void buildBackgroundView(int width) {
for (int i = 0; i < contentList.size(); i++) {
int tempindex = i;
View view = new View(context);
LinearLayout.LayoutParams viewParams = new LinearLayout.LayoutParams(width, childHeight);
view.setLayoutParams(viewParams);
view.setBackgroundColor(context.getResources().getColor(R.color.white));
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (selectedIndex != tempindex) {
setSelectedIndex(tempindex);
onSlideTabClickListener.onSlideTabClicked(tempindex);
}
selectedIndex = tempindex;
}
});
linearLayout.addView(view);
}
}
/** create highlighter view that can easily animate
* @param width
* * ***/
private void buildHighlighterView(int width) {
highLighterView = new LinearLayout(context);
highLighterView.setOrientation(LinearLayout.VERTICAL);
LayoutParams viewParams = new LayoutParams(width, parentHeight);
highLighterView.setLayoutParams(viewParams);
View view = new View(context);
LinearLayout.LayoutParams innerViewParams = new LinearLayout.LayoutParams(width, childHeight);
view.setBackgroundColor(context.getResources().getColor(R.color.black));
view.setLayoutParams(innerViewParams);
highLighterView.addView(view);
ImageView triangleImage = new ImageView(context);
LinearLayout.LayoutParams imageParmas = new LinearLayout.LayoutParams(20, 20);
imageParmas.setMargins(0, -5, 0, 0);
imageParmas.gravity = Gravity.CENTER_HORIZONTAL;
triangleImage.setLayoutParams(imageParmas);
triangleImage.setImageResource(R.drawable.ic_triangle_filled);
highLighterView.addView(triangleImage);
addView(highLighterView);
}
/** create text fields view that can easily animate
* @param width
* * ***/
private void buildTextContent(int width) {
textLayout = new LinearLayout(context);
textLayout.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 50));
for (int i = 0; i < contentList.size(); i++) {
TextView textView = new TextView(context);
textView.setText(contentList.get(i).toUpperCase());
textView.setTextSize(24);
textView.setTextColor(Color.parseColor("#000000"));
// LinearLayout.LayoutParams textParams = new LinearLayout.LayoutParams(width, ViewGroup.LayoutParams.MATCH_PARENT);
textView.setLayoutParams(new LinearLayout.LayoutParams(width, ViewGroup.LayoutParams.MATCH_PARENT));
textView.setGravity(Gravity.CENTER);
// textView.setPadding(0,10,0,10);
textLayout.addView(textView);
}
addView(textLayout);
}
public interface OnSlideTabClickListener {
void onSlideTabClicked(int index);
}
/** select the current selected index and toggle the tabs states.
* @param index
* * ***/
public void setSelectedIndex(int index) {
selectedIndex = index;
if (textLayout == null) {
return;
}
int distanceX = width * index;
ObjectAnimator animator = ObjectAnimator.ofFloat(highLighterView, "translationX", distanceX);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(400);
animator.start();
for (int i = 0; i < textLayout.getChildCount(); i++) {
TextView textView = (TextView) textLayout.getChildAt(i);
if (index == i) {
textView.setTextColor(Color.parseColor("#FFFFFF"));
} else {
textView.setTextColor(Color.parseColor("#000000"));
}
}
}
public static int getScreenWidth(Context context) {
WindowManager windowManager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(dm);
return dm.widthPixels;
}
}


Abhishek SinghalPosted Jun 14, 2023, 9:06 AM
Nice article sir
Ravikant SahuPosted Jun 14, 2023, 9:05 AM
Very informative article