Android TV控件--ScaleButton

版本更新快,很多控件再一两个版本之后就丢掉了,未免有些可惜,这里记录一个缩放按钮的控件。先看看控件长什么样子。

tv_scalebutton.gif

页面上放了4个ScaleButton控件,当触发了按钮的点击事件之后将按钮置为“选中状态”,按钮的背景色就变为红色。这个控件有四种状态,失焦(NORMAL),焦点(FOCUS),失焦&选中(NORMAL&CHOOSE),焦点&选中(FOCUS&CHOOSE)。功能不多,是一个组合控件,代码也比较简单。贴一下代码

package com.hpplay.scalebutton;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.support.annotation.DrawableRes;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by hpplay on 2016/11/10.
 */
public class ScaleButton extends RelativeLayout {

    //失焦状态
    public static final int NORMAL = 2;
    //焦点状态
    public static final int FOCUS = 4;
    //选中状态, 选中状态与(失焦/焦点)状态平行,也就是说不管当前按钮是焦点状态还是失焦状态都可以设置为选中状态
    public static final int CHOOSE = 8;

    //默认当前为失焦状态
    private int mStatus = NORMAL;

    private Context mContext;
    private int SCREEN_WIDTH;

    //按钮下方的阴影
    private ImageView mShadowView;
    private LinearLayout mContentLL;
    //按钮左侧的图片
    private ImageView mLeftView;
    //按钮右边的文字
    private TextView mDesTxt;

    //用于存储各个状态值所对应的背景色
    private Map<Integer, Integer> mColorMap = new HashMap<Integer, Integer>();

    //(失焦/焦点) & 未选中 状态对应的图片资源
    private int mImageResourceId = -1;
    //(失焦/焦点) & 选中 状态对应的图片资源
    private int mImageChooseResourceId = -1;


    public ScaleButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        init();
    }

    public ScaleButton(Context context) {
        super(context);
        this.mContext = context;
        init();
    }

    public ScaleButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        init();
    }


    private void init() {

        SCREEN_WIDTH = getScreenWidth(mContext);

        int btnHeight = getRelativeWidth(66);

        mShadowView = new ImageView(mContext);
        mShadowView.setImageResource(R.drawable.topbar_shadow);
        mShadowView.setScaleType(ImageView.ScaleType.FIT_XY);
        RelativeLayout.LayoutParams shadowParams = new LayoutParams(
                getRelativeWidth(66), getRelativeWidth(66));
        shadowParams.topMargin = getRelativeWidth(20);
        this.addView(mShadowView, shadowParams);

        mContentLL = new LinearLayout(mContext);
        mContentLL.setOrientation(LinearLayout.HORIZONTAL);
        mContentLL.setGravity(Gravity.LEFT);
        RelativeLayout.LayoutParams contentParams = new RelativeLayout.LayoutParams(
                btnHeight, btnHeight);
        contentParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
        this.addView(mContentLL, contentParams);

        mLeftView = new ImageView(mContext);
        LinearLayout.LayoutParams leftParams = new LinearLayout.LayoutParams(
                btnHeight,
                btnHeight);
        mContentLL.addView(mLeftView, leftParams);

        mDesTxt = new TextView(mContext);
        mDesTxt.setTextColor(Color.BLACK);
        mDesTxt.setTextSize(TypedValue.COMPLEX_UNIT_PX, getRelativeWidth(30));
        mDesTxt.setSingleLine(true);
        mDesTxt.setGravity(Gravity.CENTER);
        LinearLayout.LayoutParams desParams = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                btnHeight);
        mContentLL.addView(mDesTxt, desParams);


        this.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {

                int status = hasFocus ? FOCUS : NORMAL;

                if (mStatus == (NORMAL | CHOOSE)
                        || mStatus == (FOCUS | CHOOSE)) {
                    setStatus(status | CHOOSE);
                } else {
                    setStatus(status);
                }

                if (onScaleFocusChangeListener != null) {
                    onScaleFocusChangeListener
                            .onScaleBtnFocusChanged(ScaleButton.this, hasFocus);
                }
            }
        });

        this.setOnHoverListener(new OnHoverListener() {
            @Override
            public boolean onHover(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
                    requestFocus();
                }
                return false;
            }
        });


        //初始化三种状态对应的背景色
        setBackgroundColor(Color.parseColor("#ffffff"), FOCUS);
        setBackgroundColor(Color.parseColor("#CBCFD2"), NORMAL);
        setBackgroundColor(Color.parseColor("#FD765F"), CHOOSE);

        setStatus(NORMAL);

    }

    /**
     * 设置按钮的状态
     * @param status 状态值
     */
    public void setStatus(int status) {

        if (status == CHOOSE) {
            if (this.mStatus == NORMAL) {
                this.mStatus = NORMAL | CHOOSE;
            } else if (this.mStatus == FOCUS) {
                this.mStatus = FOCUS | CHOOSE;
            }
        } else {
            this.mStatus = status;
        }

        switch (mStatus) {
            case NORMAL:
                scaleContent(false, false);
                if (mImageResourceId > 0) {
                    mLeftView.setImageResource(mImageResourceId);
                }
                mContentLL.setBackgroundDrawable(getBgDrawable(mColorMap.get(NORMAL)));
                mDesTxt.setTextColor(Color.BLACK);
                break;
            case FOCUS:
                scaleContent(true, true);
                if (mImageResourceId > 0) {
                    mLeftView.setImageResource(mImageResourceId);
                }
                mContentLL.setBackgroundDrawable(getBgDrawable(mColorMap.get(FOCUS)));
                mDesTxt.setTextColor(Color.BLACK);
                break;
            case NORMAL | CHOOSE:
                scaleContent(false, false);
                if (mImageChooseResourceId > 0) {
                    mLeftView.setImageResource(mImageChooseResourceId);
                }
                mContentLL.setBackgroundDrawable(getBgDrawable(mColorMap.get(CHOOSE)));
                mDesTxt.setTextColor(Color.WHITE);
                break;
            case FOCUS | CHOOSE:
                scaleContent(true, true);
                if (mImageChooseResourceId > 0) {
                    mLeftView.setImageResource(mImageChooseResourceId);
                }
                mContentLL.setBackgroundDrawable(getBgDrawable(mColorMap.get(CHOOSE)));
                mDesTxt.setTextColor(Color.WHITE);
                break;

        }
    }

    /**
     * 清除按钮的选中状态
     */
    public void clearChooseStatus() {

        if (mStatus == (NORMAL | CHOOSE)) {
            setStatus(NORMAL);
        } else if (mStatus == (FOCUS | CHOOSE)) {
            setStatus(FOCUS);
        }

    }

    public int getStatus() {

        return mStatus;
    }


    public void setBackgroundColor(int color, int status) {
        mColorMap.put(status, color);
    }

    public void setDesTxt(String des) {
        mDesTxt.setText(des);
    }

    public void setImageResource(@DrawableRes int resourceId) {
        mImageResourceId = resourceId;
        setStatus(mStatus);
    }

    public void setChooseImageResource(@DrawableRes int resourceId) {
        mImageChooseResourceId = resourceId;
        setStatus(mStatus);
    }


    private GradientDrawable getBgDrawable(int color) {

        int roundRadius = getRelativeWidth(33); // 66/2

        GradientDrawable gd = new GradientDrawable();
        gd.setColor(color);
        gd.setCornerRadius(roundRadius);

        return gd;
    }

    private void scaleContent(boolean open, final boolean showShdowView) {
        int targetValue = 0;
        int startValue = mContentLL.getLayoutParams().width;
        if (open) {//展开
            targetValue = getRelativeWidth(184);
        } else {
            targetValue = getRelativeWidth(66);
        }

        ValueAnimator valueAnimator = ValueAnimator.ofInt(startValue, targetValue);
        valueAnimator.setDuration(300);
        valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int currentValue = (Integer) animation.getAnimatedValue();
                RelativeLayout.LayoutParams contentParams = (RelativeLayout.LayoutParams) mContentLL.getLayoutParams();
                contentParams.width = currentValue;
                mContentLL.setLayoutParams(contentParams);

                RelativeLayout.LayoutParams shadowParams = (RelativeLayout.LayoutParams) mShadowView.getLayoutParams();
                shadowParams.width = currentValue + getRelativeWidth(20);
                mShadowView.setLayoutParams(shadowParams);

                if (showShdowView) {
                    mShadowView.setAlpha(animation.getAnimatedFraction());
                } else {
                    mShadowView.setAlpha(1 - animation.getAnimatedFraction());
                }
            }
        });

        valueAnimator.start();

    }




    private OnScaleFocusChangeListener onScaleFocusChangeListener;

    public void setOnScaleFocusChangeListener(OnScaleFocusChangeListener onScaleFocusChangeListener) {
        this.onScaleFocusChangeListener = onScaleFocusChangeListener;
    }

    public interface OnScaleFocusChangeListener {
        void onScaleBtnFocusChanged(ScaleButton scaleButton, boolean focus);
    }


    public int getScreenWidth(Context context) {

        DisplayMetrics displayMetrics = new DisplayMetrics();
        WindowManager windowManager = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        return displayMetrics.widthPixels;
    }

    private int getRelativeWidth(int pxValue) {
        if (SCREEN_WIDTH <= 0) {
            return pxValue;
        }

        return (int) (pxValue * SCREEN_WIDTH / 1920.f);
    }


}

功能比较简单,就不多叙了。
看看如何使用,使用的时候可以直接写在布局文件里面,也可以直接用代码写。比较重要的就是设置下面三个属性

        ScaleButton mSetBtn = new ScaleButton(this); 
        mSetBtn.setImageResource(R.drawable.topbar_setting_black_button);
        mSetBtn.setChooseImageResource(R.drawable.topbar_setting_white_button);
        mSetBtn.setDesTxt("设置");

然后再把这个控件添加到你自己的布局中就可以了。下面贴上实现演示图片功能的代码

package com.hpplay.scalebutton;

import android.content.Intent;
import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;

public class MainActivity extends AppCompatActivity implements ScaleButton.OnScaleFocusChangeListener {

    private ScaleButton mStandardBtn;
    private ScaleButton mGameBtn;
    private ScaleButton mSetBtn;
    private ScaleButton mHelpBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        RelativeLayout rootLayout = (RelativeLayout) View.inflate(this, R.layout.activity_main, null);
        setContentView(rootLayout);
        init(rootLayout);

    }

    private void init(RelativeLayout relativeLayout) {

        mSetBtn = new ScaleButton(this);
        mSetBtn.setId(30003);
        mSetBtn.setFocusable(true);
        mSetBtn.setFocusableInTouchMode(true);
        mSetBtn.setClickable(true);
        RelativeLayout.LayoutParams setParams = new RelativeLayout.LayoutParams
                (ViewGroup.LayoutParams.WRAP_CONTENT
                        , ViewGroup.LayoutParams.WRAP_CONTENT);
        setParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        setParams.topMargin = 20;
        relativeLayout.addView(mSetBtn, setParams);

        mSetBtn.setImageResource(R.drawable.topbar_setting_black_button);
        mSetBtn.setChooseImageResource(R.drawable.topbar_setting_white_button);
        mSetBtn.setDesTxt("设置");


        mHelpBtn = new ScaleButton(this);
        mHelpBtn.setFocusable(true);
        mHelpBtn.setFocusableInTouchMode(true);
        mHelpBtn.setClickable(true);
        mHelpBtn.setId(30002);
        RelativeLayout.LayoutParams helpParams = new RelativeLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT
                , ViewGroup.LayoutParams.WRAP_CONTENT);
        helpParams.addRule(RelativeLayout.LEFT_OF, mSetBtn.getId());
        helpParams.addRule(RelativeLayout.ALIGN_TOP, mSetBtn.getId());
        relativeLayout.addView(mHelpBtn, helpParams);

        mHelpBtn.setImageResource(R.drawable.topbar_help_black_button);
        mHelpBtn.setChooseImageResource(R.drawable.topbar_help_white_button);
        mHelpBtn.setDesTxt("帮助");


        mGameBtn = new ScaleButton(this);
        mGameBtn.setFocusableInTouchMode(true);
        mGameBtn.setFocusable(true);
        mGameBtn.setClickable(true);
        mGameBtn.setId(30001);
        RelativeLayout.LayoutParams gameParams = new RelativeLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT
                , ViewGroup.LayoutParams.WRAP_CONTENT);
        gameParams.addRule(RelativeLayout.ALIGN_TOP, mHelpBtn.getId());
        gameParams.addRule(RelativeLayout.LEFT_OF, mHelpBtn.getId());
        relativeLayout.addView(mGameBtn, gameParams);

        mGameBtn.setDesTxt("游戏");
        mGameBtn.setImageResource(R.drawable.topbar_game_black_button);
        mGameBtn.setChooseImageResource(R.drawable.topbar_game_white_button);


        mStandardBtn = new ScaleButton(this);
        mStandardBtn.setFocusable(true);
        mStandardBtn.setFocusableInTouchMode(true);
        mStandardBtn.setClickable(true);
        mStandardBtn.setId(30000);
        RelativeLayout.LayoutParams standardParams = new RelativeLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT
                , ViewGroup.LayoutParams.WRAP_CONTENT);
        standardParams.addRule(RelativeLayout.ALIGN_TOP, mHelpBtn.getId());
        standardParams.addRule(RelativeLayout.LEFT_OF, mGameBtn.getId());
        relativeLayout.addView(mStandardBtn, standardParams);

        mStandardBtn.setDesTxt("标准");
        mStandardBtn.setImageResource(R.drawable.topbar_home_black_button);
        mStandardBtn.setChooseImageResource(R.drawable.topbar_home_white_button);


        mSetBtn.setNextFocusRightId(mStandardBtn.getId());
        mStandardBtn.setNextFocusLeftId(mSetBtn.getId());

        mStandardBtn.setOnScaleFocusChangeListener(this);
        mGameBtn.setOnScaleFocusChangeListener(this);
        mSetBtn.setOnScaleFocusChangeListener(this);
        mHelpBtn.setOnScaleFocusChangeListener(this);

        View.OnClickListener onClickListener = new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (view instanceof ScaleButton) {
                    clearBtnChooseStatus();
                    ((ScaleButton) view).setStatus(ScaleButton.CHOOSE);
                }
            }
        };

        mSetBtn.setOnClickListener(onClickListener);
        mHelpBtn.setOnClickListener(onClickListener);
        mGameBtn.setOnClickListener(onClickListener);
        mStandardBtn.setOnClickListener(onClickListener);

    }

    /**
     * 清除所有按钮的选中状态
     */
    private void clearBtnChooseStatus() {
        mSetBtn.clearChooseStatus();
        mHelpBtn.clearChooseStatus();
        mGameBtn.clearChooseStatus();
        mStandardBtn.clearChooseStatus();
    }

    @Override
    public void onScaleBtnFocusChanged(ScaleButton scaleButton, boolean focus) {

        if (scaleButton == mSetBtn) {//mSetBtn获取到焦点

        } else if (scaleButton == mHelpBtn) {//mHelpBtn获取到焦点

        } else if (scaleButton == mGameBtn) {//mGameBtn获取到焦点

        } else if (scaleButton == mStandardBtn) {//mStandardBtn获取到焦点

        }


    }

}

最简单的MainActivity,布局文件也比较简单,就是一个空的Relativelayout,新建项目默认生成的。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.hpplay.scalebutton.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
</RelativeLayout>

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容