public class

ThumbsBar

extends LinearLayout

 java.lang.Object

↳LinearLayout

↳androidx.leanback.widget.ThumbsBar

Gradle dependencies

compile group: 'androidx.leanback', name: 'leanback', version: '1.2.0-alpha02'

  • groupId: androidx.leanback
  • artifactId: leanback
  • version: 1.2.0-alpha02

Artifact androidx.leanback:leanback:1.2.0-alpha02 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.leanback:leanback com.android.support:leanback-v17

Androidx class mapping:

androidx.leanback.widget.ThumbsBar android.support.v17.leanback.widget.ThumbsBar

Summary

Constructors
publicThumbsBar(Context context, AttributeSet attrs)

publicThumbsBar(Context context, AttributeSet attrs, int defStyle)

Methods
public voidclearThumbBitmaps()

Clear all thumb bitmaps set on thumb views.

protected ViewcreateThumbView(ViewGroup parent)

Create a thumb view, it's by default a ImageView.

public intgetHeroIndex()

Get hero index which is the middle child.

public BitmapgetThumbBitmap(int index)

Get bitmap of given child index.

protected voidonLayout(boolean changed, int l, int t, int r, int b)

protected voidonMeasure(int widthMeasureSpec, int heightMeasureSpec)

public voidsetHeroThumbSize(int width, int height)

Set size of hero thumb view in pixels, it is usually larger than other thumbs.

public voidsetNumberOfThumbs(int numOfThumbs)

Set number of thumb views.

public voidsetThumbBitmap(int index, Bitmap bitmap)

Set thumb bitmap for a given index of child.

public voidsetThumbSize(int width, int height)

Set size of thumb view in pixels

public voidsetThumbSpace(int spaceInPixel)

Set the space between thumbs in pixels

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public ThumbsBar(Context context, AttributeSet attrs)

public ThumbsBar(Context context, AttributeSet attrs, int defStyle)

Methods

public int getHeroIndex()

Get hero index which is the middle child.

public void setThumbSize(int width, int height)

Set size of thumb view in pixels

public void setHeroThumbSize(int width, int height)

Set size of hero thumb view in pixels, it is usually larger than other thumbs.

public void setThumbSpace(int spaceInPixel)

Set the space between thumbs in pixels

public void setNumberOfThumbs(int numOfThumbs)

Set number of thumb views.

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

protected void onLayout(boolean changed, int l, int t, int r, int b)

protected View createThumbView(ViewGroup parent)

Create a thumb view, it's by default a ImageView.

public void clearThumbBitmaps()

Clear all thumb bitmaps set on thumb views.

public Bitmap getThumbBitmap(int index)

Get bitmap of given child index.

public void setThumbBitmap(int index, Bitmap bitmap)

Set thumb bitmap for a given index of child.

Source

/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * 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 androidx.leanback.widget;

import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

import androidx.annotation.RestrictTo;
import androidx.leanback.R;

/**
 * @hide
 */
@RestrictTo(LIBRARY_GROUP_PREFIX)
public class ThumbsBar extends LinearLayout {

    // initial value for Thumb's number before measuring the screen size
    int mNumOfThumbs = -1;
    int mThumbWidthInPixel;
    int mThumbHeightInPixel;
    int mHeroThumbWidthInPixel;
    int mHeroThumbHeightInPixel;
    int mMeasuredMarginInPixel;
    final SparseArray<Bitmap> mBitmaps = new SparseArray<>();

    // flag to determine if the number of thumbs in thumbs bar is set by user through
    // setNumberofThumbs API or auto-calculated according to android tv design spec.
    private boolean mIsUserSets = false;

    public ThumbsBar(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ThumbsBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // According to the spec,
        // the width of non-hero thumb should be 80% of HeroThumb's Width, i.e. 0.8 * 192dp = 154dp
        mThumbWidthInPixel = context.getResources().getDimensionPixelSize(
                R.dimen.lb_playback_transport_thumbs_width);
        mThumbHeightInPixel = context.getResources().getDimensionPixelSize(
                R.dimen.lb_playback_transport_thumbs_height);
        // According to the spec, the width of HeroThumb should be 192dp
        mHeroThumbHeightInPixel = context.getResources().getDimensionPixelSize(
                R.dimen.lb_playback_transport_hero_thumbs_width);
        mHeroThumbWidthInPixel = context.getResources().getDimensionPixelSize(
                R.dimen.lb_playback_transport_hero_thumbs_height);
        // According to the spec, the margin between thumbs to be 4dp
        mMeasuredMarginInPixel = context.getResources().getDimensionPixelSize(
                R.dimen.lb_playback_transport_thumbs_margin);
    }

    /**
     * Get hero index which is the middle child.
     */
    public int getHeroIndex() {
        return getChildCount() / 2;
    }

    /**
     * Set size of thumb view in pixels
     */
    public void setThumbSize(int width, int height) {
        mThumbHeightInPixel = height;
        mThumbWidthInPixel = width;
        int heroIndex = getHeroIndex();
        for (int i = 0; i < getChildCount(); i++) {
            if (heroIndex != i) {
                View child = getChildAt(i);
                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
                boolean changed = false;
                if (lp.height != height) {
                    lp.height = height;
                    changed = true;
                }
                if (lp.width != width) {
                    lp.width = width;
                    changed = true;
                }
                if (changed) {
                    child.setLayoutParams(lp);
                }
            }
        }
    }

    /**
     * Set size of hero thumb view in pixels, it is usually larger than other thumbs.
     */
    public void setHeroThumbSize(int width, int height) {
        mHeroThumbHeightInPixel = height;
        mHeroThumbWidthInPixel = width;
        int heroIndex = getHeroIndex();
        for (int i = 0; i < getChildCount(); i++) {
            if (heroIndex == i) {
                View child = getChildAt(i);
                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
                boolean changed = false;
                if (lp.height != height) {
                    lp.height = height;
                    changed = true;
                }
                if (lp.width != width) {
                    lp.width = width;
                    changed = true;
                }
                if (changed) {
                    child.setLayoutParams(lp);
                }
            }
        }
    }

    /**
     * Set the space between thumbs in pixels
     */
    public void setThumbSpace(int spaceInPixel) {
        mMeasuredMarginInPixel = spaceInPixel;
        requestLayout();
    }

    /**
     * Set number of thumb views.
     */
    public void setNumberOfThumbs(int numOfThumbs) {
        mIsUserSets = true;
        mNumOfThumbs = numOfThumbs;
        setNumberOfThumbsInternal();
    }

    /**
     * Helper function for setNumberOfThumbs.
     * Will Update the layout settings in ThumbsBar based on mNumOfThumbs
     */
    private void setNumberOfThumbsInternal() {
        while (getChildCount() > mNumOfThumbs) {
            removeView(getChildAt(getChildCount() - 1));
        }
        while (getChildCount() < mNumOfThumbs) {
            View view = createThumbView(this);
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(mThumbWidthInPixel,
                    mThumbHeightInPixel);
            addView(view, lp);
        }
        int heroIndex = getHeroIndex();
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
            if (heroIndex == i) {
                lp.width = mHeroThumbWidthInPixel;
                lp.height = mHeroThumbHeightInPixel;
            } else {
                lp.width = mThumbWidthInPixel;
                lp.height = mThumbHeightInPixel;
            }
            child.setLayoutParams(lp);
        }
    }

    private static int roundUp(int num, int divisor) {
        return (num + divisor - 1) / divisor;
    }

    /**
     * Helper function to compute how many thumbs should be put in the screen
     * Assume we should put x's non-hero thumbs in the screen, the equation should be
     *   192dp (width of hero thumbs) +
     *   154dp (width of common thumbs) * x +
     *   4dp (width of the margin between thumbs) * x
     *     = width
     * So the calculated number of non-hero thumbs should be (width - 192dp) / 158dp.
     * If the calculated number of non-hero thumbs is less than 2, it will be updated to 2
     * or if the calculated number or non-hero thumbs is not an even number, it will be
     * decremented by one.
     * This processing is used to make sure the arrangement of non-hero thumbs
     * in ThumbsBar is symmetrical.
     * Also there should be a hero thumb in the middle of the ThumbsBar,
     * the final result should be non-hero thumbs (after processing) + 1.
     *
     * @param  widthInPixel measured width in pixel
     * @return The number of thumbs
     */
    private int calculateNumOfThumbs(int widthInPixel) {
        int nonHeroThumbNum = roundUp(widthInPixel - mHeroThumbWidthInPixel,
                mThumbWidthInPixel + mMeasuredMarginInPixel);
        if (nonHeroThumbNum < 2) {
            // If the calculated number of non-hero thumbs is less than 2,
            // it will be updated to 2
            nonHeroThumbNum = 2;
        } else if ((nonHeroThumbNum & 1) != 0) {
            // If the calculated number or non-hero thumbs is not an even number,
            // it will be increased by one.
            nonHeroThumbNum++;
        }
        // Count Hero Thumb to the final result
        return nonHeroThumbNum + 1;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = getMeasuredWidth();
        // If the number of thumbs in ThumbsBar is not set by user explicitly, it will be
        // recalculated based on Android TV Design Spec
        if (!mIsUserSets) {
            int numOfThumbs = calculateNumOfThumbs(width);
            // Set new number of thumbs when calculation result is different with current number
            if (mNumOfThumbs != numOfThumbs) {
                mNumOfThumbs = numOfThumbs;
                setNumberOfThumbsInternal();
            }
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        int heroIndex = getHeroIndex();
        View heroView = getChildAt(heroIndex);
        int heroLeft = getWidth() / 2 - heroView.getMeasuredWidth() / 2;
        int heroRight = getWidth() / 2 + heroView.getMeasuredWidth() / 2;
        heroView.layout(heroLeft, getPaddingTop(), heroRight,
                getPaddingTop() + heroView.getMeasuredHeight());
        int heroCenter = getPaddingTop() + heroView.getMeasuredHeight() / 2;

        for (int i = heroIndex - 1; i >= 0; i--) {
            heroLeft -= mMeasuredMarginInPixel;
            View child = getChildAt(i);
            child.layout(heroLeft - child.getMeasuredWidth(),
                    heroCenter - child.getMeasuredHeight() / 2,
                    heroLeft,
                    heroCenter + child.getMeasuredHeight() / 2);
            heroLeft -= child.getMeasuredWidth();
        }
        for (int i = heroIndex + 1; i < mNumOfThumbs; i++) {
            heroRight += mMeasuredMarginInPixel;
            View child = getChildAt(i);
            child.layout(heroRight,
                    heroCenter - child.getMeasuredHeight() / 2,
                    heroRight + child.getMeasuredWidth(),
                    heroCenter + child.getMeasuredHeight() / 2);
            heroRight += child.getMeasuredWidth();
        }
    }

    /**
     * Create a thumb view, it's by default a ImageView.
     */
    protected View createThumbView(ViewGroup parent) {
        return new ImageView(parent.getContext());
    }

    /**
     * Clear all thumb bitmaps set on thumb views.
     */
    public void clearThumbBitmaps() {
        for (int i = 0; i < getChildCount(); i++) {
            setThumbBitmap(i, null);
        }
        mBitmaps.clear();
    }


    /**
     * Get bitmap of given child index.
     */
    public Bitmap getThumbBitmap(int index) {
        return mBitmaps.get(index);
    }

    /**
     * Set thumb bitmap for a given index of child.
     */
    public void setThumbBitmap(int index, Bitmap bitmap) {
        mBitmaps.put(index, bitmap);
        ((ImageView) getChildAt(index)).setImageBitmap(bitmap);
    }
}