Skip to content

tracyliu1/LoopLayout

Repository files navigation

LoopLayout

a Layout for TV Launcher

需求:选中的Item要有动画效果;Launcher主页上的Item支持循环。点击非选中item后,item来到中间选中位置。

自定义控件一般可以分为两种:继承控件、复合控件。前者是通过继承View或其子类,重写onDraw()方法来绘制View的显示内容。后者通常继承ViewGroup及其子类(LinearLayout、RelativeLayout、FrameLayout等),内部添加其他控件,从而组合成新的复合控件。本次即为复合控件。

通常来说,我们会定义好一个layout.xml文件,然后在构造器中通过调用inflate(R.layout.my_layout,this,true)加载该xml文件。可以在构造器或onFinishInflate()方法来获取(建议第二种,保证控件已经完全加载好)子控件对象,然后设置属性。

值得注意的两点:

1.在构造器中通过调用inflate(R.layout.my_layout,this,true)加载该xml文件。可以在构造器或onFinishInflate()方法来获取(建议第二种,保证控件已经完全加载好)子控件对象;

2.如果需要从资源文件中加载该自定义控件,则必须重写Constructor(Context context, AttributeSet attrs)此构造方法;

public LoopLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    mContext = context;
    mSelectNames = getResources().getStringArray(R.array.dtv_select);
    initViews();
}
//从xml Inflate view
public LoopLayout(Context context) {
    super(context);
    mContext = context;
    mSelectNames = getResources().getStringArray(R.array.dtv_select);
    initViews();
}

两个构造方法,区别为在代码中创建View的时候用View(Context),从xml Inflate view的时候重写View(Context,Attributeset)。

 private void initViews() {

        mLooplist = new ArrayList<>();
        for (int i = 0; i < mDTVAnim.length; i++) {
            LauncherBean bean = new LauncherBean(mDTVAnim[i], mDTVFronts[i], mDTVImages[i], mSelectNames[i]);
            mLooplist.add(bean);
        }

        LOOP_NUM = mLooplist.size();

        //attachToRoot必须为true 否则不能添加到root布局
        View view = LayoutInflater.from(mContext).inflate(R.layout.loop, this, true);
        mTextView01 = (TextView) view.findViewById(R.id.tv_01);
        mTextView02 = (TextView) view.findViewById(R.id.tv_02);
        mTextView03 = (TextView) view.findViewById(R.id.tv_03);
        mTextView04 = (TextView) view.findViewById(R.id.tv_04);
        mTextView05 = (TextView) view.findViewById(R.id.tv_05);

        mImageView01 = (ImageView) view.findViewById(R.id.iv_01);
        mImageView02 = (ImageView) view.findViewById(R.id.iv_02);
        mImageView03 = (ImageView) view.findViewById(R.id.iv_03);
        mImageView04 = (ImageView) view.findViewById(R.id.iv_04);
        mImageView05 = (ImageView) view.findViewById(R.id.iv_05);

        iv_left_arrow = view.findViewById(R.id.iv_left_arrow);
        iv_right_arrow = view.findViewById(R.id.iv_right_arrow);

        mImageView01.setOnClickListener(this);
        mImageView02.setOnClickListener(this);
        mImageView04.setOnClickListener(this);
        mImageView05.setOnClickListener(this);

        iv_left_arrow.setOnClickListener(this);
        iv_right_arrow.setOnClickListener(this);

        setViews(0, true);
    }

有焦点的时候播放动画

@Override
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
    super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);

    if (gainFocus) {
        setViews(mPosition, true);
        AnimationDrawable animationDrawable = (AnimationDrawable) mImageView03.getBackground();
        animationDrawable.run();
    } else {
        setViews(mPosition, false);
    }
}

支持遥控器操作

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {

    if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
        mPosition++;
    } else if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_DPAD_LEFT){
        mPosition--;
    }

    int positon = syncPosition(mPosition);
    setViews(positon, true);

    if (mSelectListener != null) {
        int index = syncPosition(mPosition + 2);
        mSelectListener.onItemselect(index);
    }
    return super.onKeyDown(keyCode, event);
}

同步index位置

private int syncPosition(int index) {

    if (index < 0) {
        index = LOOP_NUM - 1;
    } else if (index > LOOP_NUM - 1) {
        index = index % LOOP_NUM;
    }
    return index;
}

支持点击

@Override
public void onClick(View v) {

    switch (v.getId()) {
        case R.id.iv_01:
            mPosition = mPosition - 2;
            break;
        case R.id.iv_02:
            mPosition = mPosition - 1;
            break;
        case R.id.iv_04:
            mPosition = mPosition + 1;
            break;
        case R.id.iv_05:
            mPosition = mPosition + 2;
            break;
        case R.id.iv_left_arrow:
            mPosition--;
            break;
        case R.id.iv_right_arrow:
            mPosition++;
            break;
        default:
            break;
    }

    int position = syncPosition(mPosition);
    setViews(position, true);
}

About

a Layout for TV Launcher

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages