Android TV控件--ScaleButton

0.124字数 296阅读 439

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

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>

推荐阅读更多精彩内容