티스토리 뷰

Custom Android TabWidget with Badges

Written by  on August 16, 2011 in Dev Blog - 7 Comments

For an android app I’m working on I needed to present badges for tabs much like on the iPhone. I looked around for a bit but could not find any good solution for this. It seems the android SDK does not provide this feature out of the box. At least I could not find it. So I had a go at writing a custom TabWidget for this nifty feature.

I’m sure it can be made to look even better with some work. The icon is not the most pretty image and should probably be replaced. Called badge.png in the source files.

I used a singleton class BadgeTabManager to manage the tabs and get access to them from anywhere in the app. I guess this approach could be changed if several tabwidgets need to be used at the same time.

The badges are set by a simple call:

BadgeTabManager.getInstance().setBadgeAtIndex(5, 2);

The BadgeTabWidget looks like this:

/*
 * Copyright (C) 2011 Nilisoft
 *
 * 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.
 */
package com.nilisoft.examples.badgetabs;

import java.util.HashMap;

import com.nilisoft.examples.R;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TabWidget;

public class BadgeTabWidget extends TabWidget{

 HashMap<integer badge=""> map;

 public BadgeTabWidget(Context context) {
  super(context);

  map = new HashMap<integer badge="">();

 }

 public BadgeTabWidget(Context c, AttributeSet set){
  super(c, set);

  map = new HashMap<integer badge="">();
 }

 public int getBadgeNumAtIndex(int index){
  Badge b = map.get(index);
  if (b == null){
   return 0;
  }
  else{
   return b.getNum();
  }
 }

 public void setBadgeAtIndex(int num, int index){
  Badge b = map.get(index);
  if (b == null){
   b = new Badge();
   map.put(index, b);
  }
  b.setNum(num);
public void setBadgeAtIndex(int num, int index){
  Badge b = map.get(index);
  if (b == null){
   b = new Badge();
   map.put(index, b);
  }
  b.setNum(num);

  // should probably use some other way to update the view (repaint the tabs) but this works...
  this.getChildAt(index).setVisibility(View.INVISIBLE);
  this.getChildAt(index).setVisibility(View.VISIBLE);
 }

 }

 @Override
 protected boolean drawChild (Canvas canvas, View child, long drawingTime){
  boolean b = super.drawChild(canvas, child, drawingTime);

  // figure out our index in the tabs, need it for the badge number
  int index = 0;
  for(int i=0; i < this.getTabCount(); i++){
   if (this.getChildAt(i) == child){
    index = i;
    break;
   }
  }

  int num = this.getBadgeNumAtIndex(index);

  if (num > 0){
   Bitmap src = BitmapFactory.decodeResource(this.getResources(),R.drawable.badge);
   Bitmap badge = Bitmap.createScaledBitmap(src, 24, 19, true);

   int x =  child.getRight()-badge.getWidth()-5;

   canvas.drawBitmap(badge, x, 0, new Paint());

   Typeface face = Typeface.create("Verdana", Typeface.BOLD);
   Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
   paint.setTypeface(face);
   paint.setTextSize(12);
   paint.setARGB(255, 255, 255, 255);

   String text = ""+num;
   Rect bounds = new Rect();
   paint.getTextBounds(text, 0, text.length(), bounds);

   canvas.drawText(
     text,
     (x+badge.getWidth()/2)-bounds.width()/2,
     // -1 here because the badge icon is looking as it does with some
     // more space at the bottom for shadows, might need change if the
     // size of the icon is changed
     (badge.getHeight()/2)+bounds.height()/2 -2,
     paint);

  }

  return b;
 }

 private class Badge {
  int num;

  public Badge(){
   num = 0;
  }

  public void setNum(int num){
   this.num = num;
  }

  public int getNum(){
   return num;
  }

 }

}
</integer></integer></integer>

And the full source code the for example project can be downloaded here: BadgeTabs

Enjoy! And please let me know if you find this useful in any of your apps.

The end result looks like this:

댓글

파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음



Total
Today
Yesterday
최근에 달린 댓글