自定义GridView的使用(盒子应用)

突然发现好久没有写博客了,一直放到笔记里面,今天update一下。


最近做的一个项目中,是盒子+电视,用户通过遥控器来操作。
这里只是说下GridView在当前业务下的简单使用,其实效果可以更多,实现的方式可以更高级。
比如下面这个开源项目:https://github.com/FrozenFreeFall/Android-tv-widget

描述:一个界面里面有多个Item选项,当进入到页面后,默认选中第一个Item,并更新Item的背景为选中状态,并且该GridView有OnItemSelectedListener和onItemClickListener以及OnLayoutChange监听,使用OK按钮,可以实现点击效果。

自定义控件MyGridView.java

package com.shenqijiazu.daillylesson.widget;

import com.shenqijiazu.daillylesson.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnLayoutChangeListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.GridView;

/**
 * @author xxiang1x
 * 
 *         教师界面、班级界面、等都用到GridView,这个把公共部分提取出来。比如选中效果,制作成自定义控件。
 */
public class MyGridView extends GridView implements OnLayoutChangeListener,
        android.widget.AdapterView.OnItemSelectedListener,
        android.widget.AdapterView.OnItemClickListener {

    /**
     * 被选中的GridView's adapter's item.xml中,对应布局layout。用于设置背景
     */
    private int selectedLayoutResId = -1;
    /**
     * 未被选中时候的背景
     */
    private int unSelectedResBgId = -1;
    /**
     * 被选中时候的背景
     */
    private int selectedResBgId = -1;
    /**
     * 布局layout的名字。因为这个布局是Adapter里面item的布局id,所以我们这里用name来绑定到对应的id layout
     */
    private String selectedItemLayoutName;

    public MyGridView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
        initMonitors();
    }

    /**
     * 设置监听
     */
    private void initMonitors() {
        // TODO Auto-generated method stub
        this.setOnItemSelectedListener(this);
        this.addOnLayoutChangeListener(this);
        this.setOnItemClickListener(this);
        this.setFocusable(true);
        this.setFocusableInTouchMode(true);
    }

    public MyGridView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initMonitors();
        // TODO Auto-generated constructor stub

        initAttributes(context, attrs, defStyle);
    }

    /**
     * Get自定义属性。
     * 
     * @param context
     * @param attrs
     * @param defStyle
     */
    private void initAttributes(Context context, AttributeSet attrs,
            int defStyle) {
        // TODO Auto-generated method stub
        TypedArray a = null;
        try {

            // a = context.obtainStyledAttributes(attrs,
            // R.styleable.MagicGridView, defStyle, 0);
            a = context
                    .obtainStyledAttributes(attrs, R.styleable.MagicGridView);

            selectedResBgId = a.getResourceId(
                    R.styleable.MagicGridView_selected_item_background, -1);
            unSelectedResBgId = a.getResourceId(
                    R.styleable.MagicGridView_unselected_item_background, -1);

            selectedItemLayoutName = a
                    .getString(R.styleable.MagicGridView_selected_item_layout_name);
            if (!TextUtils.isEmpty(selectedItemLayoutName)) {
                // 听过设定layout的名字去获取对应的id
                selectedLayoutResId = a.getResources().getIdentifier(
                        selectedItemLayoutName, "id", context.getPackageName());
            }
        } finally {

            a.recycle();
        }
    }

    public MyGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initMonitors();
        // TODO Auto-generated constructor stub
        initAttributes(context, attrs, -1);
    }

    @Override
    public void onLayoutChange(View v, int left, int top, int right,
            int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
        // TODO Auto-generated method stub

        this.setSelection(0);

    }

    /**
     * 记录之前的被选中的View
     */
    private int mPrevPosition = -1;

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position,
            long id) {
        // TODO Auto-generated method stub

        responseSelectAndClick(parent, view, position, id);

    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {
        // TODO Auto-generated method stub

    }

    /**
     * 响应选择和点击效果。
     * 
     * @param parent
     * @param view
     * @param position
     * @param id
     */
    private void responseSelectAndClick(AdapterView<?> parent, View view,
            int position, long id) {
        // TODO Auto-generated method stub
        if (null != view) {
            if (selectedLayoutResId == -1 || selectedResBgId == -1
                    || unSelectedResBgId == -1) {

                return;
            }
            if (mPrevPosition != -1 && mPrevPosition != position) {
                // 首先恢复状态
                ViewGroup mPrevViewGroup = (ViewGroup) parent
                        .getChildAt(mPrevPosition);
                if (null != mPrevViewGroup) {

                    ((ViewGroup) mPrevViewGroup).findViewById(
                            selectedLayoutResId).setBackgroundResource(
                            unSelectedResBgId);
                }
            }
            if (mPrevPosition != position) {
                // 把选中状态设置到新的View
                mPrevPosition = position;
                ((ViewGroup) view).findViewById(selectedLayoutResId)
                        .setBackgroundResource(selectedResBgId);
            }
        }
    }

    /**
     * <p>
     * 如果动态创建的GridView则使用这个方式设置对应值。
     * </p>
     * <p>
     * 如果是xml中配置则使用自定义属性添加到xml中。
     * </p>
     * 
     * @param layoutResId
     * @param bgSelectedResId
     * @param unSelectedResId
     */
    public void setSelectedEffectRes(int layoutResId, int bgSelectedResId,
            int unSelectedResId) {

        this.selectedLayoutResId = layoutResId;
        this.selectedResBgId = bgSelectedResId;
        this.unSelectedResBgId = unSelectedResId;
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
            long id) {
        // TODO Auto-generated method stub
        onItemClickCallBack.onItemClick(parent, view, position, id);
        // 点击也加上效果。
        responseSelectAndClick(parent, view, position, id);
    }

    private OnItemClickCallBack onItemClickCallBack;

    public void setOnItemClickCallBack(OnItemClickCallBack onItemClickCallBack) {
        this.onItemClickCallBack = onItemClickCallBack;
    }

    public interface OnItemClickCallBack {
        void onItemClick(AdapterView<?> parent, View view, int position, long id);

    }
}

自定义相关属性:

    <!-- MyGridView自定义属性 -->
    <declare-styleable name="MagicGridView">
        <attr name="selected_item_layout_name" format="string"></attr>
        <attr name="selected_item_background" format="reference"></attr>
        <attr name="unselected_item_background" format="reference"></attr>
    </declare-styleable>
  • selected_item_layout_name对应的是该界面的GridView所使用的Adapter的Item布局中外层Layout的resource id。
  • selected_item_background对应Item为选中状态时候的背景
  • unselected_item_background对应Item为非选中状态时候的背景

在xml中的定义:

<com.androidtest.widget.MyGridView
                android:id="@+id/gv_classinfos"
                android:layout_width="782dip"
                android:layout_height="300dip"
                android:layout_centerHorizontal="true"
                android:layout_marginLeft="100dip"
                android:layout_marginRight="100dip"
                android:layout_marginTop="170dip"
                android:horizontalSpacing="10dip"
                android:listSelector="#00000000"
                android:numColumns="3"
                android:scrollbars="none"
                android:verticalSpacing="20dp" app:selected_item_background="@drawable/dialog_classinfo_item_pressed"
                app:selected_item_layout_name="dialog_classes_bglayout"
                app:unselected_item_background="@drawable/dialog_classinfo_item_normal" >
            </com.shenqijiazu.daillylesson.widget.MyGridView>

其中的重点在于下面属性的定义:

app:selected_item_background="@drawable/dialog_classinfo_item_pressed"
                app:selected_item_layout_name="dialog_classes_bglayout"
                app:unselected_item_background="@drawable/dialog_classinfo_item_normal"

对应的MyGridView.java中的解析:

private void initAttributes(Context context, AttributeSet attrs,
            int defStyle) {
        // TODO Auto-generated method stub
        TypedArray a = null;
        try {

            // a = context.obtainStyledAttributes(attrs,
            // R.styleable.MagicGridView, defStyle, 0);
            a = context
                    .obtainStyledAttributes(attrs, R.styleable.MagicGridView);

            selectedResBgId = a.getResourceId(
                    R.styleable.MagicGridView_selected_item_background, -1);
            unSelectedResBgId = a.getResourceId(
                    R.styleable.MagicGridView_unselected_item_background, -1);

            selectedItemLayoutName = a
                    .getString(R.styleable.MagicGridView_selected_item_layout_name);
            if (!TextUtils.isEmpty(selectedItemLayoutName)) {
                // 听过设定layout的名字去获取对应的id
                selectedLayoutResId = a.getResources().getIdentifier(
                        selectedItemLayoutName, "id", context.getPackageName());
            }
        } finally {

            a.recycle();
        }
    }

因为xml中无法指定别的xml文件里面对应id的layout,所以这里使用a.getResources().getIdentifier方法,利用layout的name获取到对应的layout resource id ,此时就绑定了Adapter Item布局中对应id的ViewGroup,这样就可以进行其他的操作了。

selectedItemLayoutName = a
                    .getString(R.styleable.MagicGridView_selected_item_layout_name);
            if (!TextUtils.isEmpty(selectedItemLayoutName)) {
                // 听过设定layout的名字去获取对应的id
                selectedLayoutResId = a.getResources().getIdentifier(
                        selectedItemLayoutName, "id", context.getPackageName());
            }

最后说一下mPrevPosition这个变量,主要在responseSelectAndClick()方法中使用。当使用遥控左右上下切换的时候,我们需要将前一个的背景还原,新的选中item更新背景。
这里写图片描述

因为某些原因,图片信息不能透露过多。就简单截屏一两个效果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值