1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > android tv 焦点居中自定义listview控件的实现

android tv 焦点居中自定义listview控件的实现

时间:2020-03-29 00:55:33

相关推荐

android tv 焦点居中自定义listview控件的实现

因为项目需要,花了一天做了一个自定义listview,和google官方效果图上的控件类似,效果图:

即焦点始终在屏幕中央,焦点选中的item被放大,且颜色被改变,遥控器可以指挥listview上下滚动并且选择,要做到这个首先要想清楚思路:

核心思想

1、中间的“焦点”不是真实的焦点,是画出来的。

2、移动listview使用的方法是listview.smoothScrollBy,但当选择到前几个item或后几个item时,会有留白的情况,如图,为了解决这个问题,我有想过整体移动listview,最后由于越搞越麻烦而放弃,在这里使用了控制adapter,使其产生空白选项,这样不用移动listview也能解决此问题。

3、对于移动状态进行监听,发现移动产生后改变item中字体的效果。

对于以上的核心思想,做几点解释:

1、我们使用listview.setSelection()方法使焦点移动到想要的item上,但是频繁调用这个方法会让焦点出现闪烁的情况,尤其是在自定义了焦点的样式后,这种情况比较明显。为了保证在移动时控件的美观,我们使用绘制矩阵的方式,将焦点画出来。

下面上代码,该有注释的地方都有:

package com.pu.test;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.ColorFilter;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.os.Handler;import android.os.Looper;import android.util.AttributeSet;import android.util.Log;import android.util.TypedValue;import android.view.KeyEvent;import android.view.View;import android.view.ViewGroup;import android.widget.AbsListView;import android.widget.ListAdapter;import android.widget.ListView;import android.widget.TextView;import java.util.List;/*** 通用型焦点始终位于中心且带滚动动画的listview* * @author puky*/public class WheelListView extends ListView {public static final String TAG = WheelListView.class.getSimpleName();private static final int COLOR_SOLID_SELET_DEFAULT = Color.parseColor("#E01F1F");// total of several item are displayed by defaultprivate static final int WHEEL_SIZE_DEFAULT = 3; //Callback delay timeprivate static final int MIN_TIME = 300; private static final int HANDLER_LISTENER = 99;private static final int LAST_HANDLER_LISTENER = 100;//The size of the data used for the calculationprivate int mDataSize = 0;private int mLabelSelectColor = Color.WHITE;private int mLabelColor = Color.GRAY;private float mAlphaGradual = 0.5f;private int seletedSolidColor = COLOR_SOLID_SELET_DEFAULT;private int mWheelSize = WHEEL_SIZE_DEFAULT;private int mItemHeight;private int mItemWidth;private int mCurrentPositon;private Paint seletedSolidPaint;private boolean isRecover = false;private int proSelection = 0;private int curSelection = 0;private WheelItemSelectedListener mItemSelectedListener;public WheelListView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}public WheelListView(Context context, AttributeSet attrs) {super(context, attrs);init();}public WheelListView(Context context) {super(context);}private void init() {setVerticalScrollBarEnabled(false); // Hide the scroll barsetCacheColorHint(Color.TRANSPARENT);setOverScrollMode(OVER_SCROLL_NEVER);setDividerHeight(0);seletedSolidPaint = new Paint();seletedSolidPaint.setColor(seletedSolidColor);setOnScrollListener(new OnScrollListener() {@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {// Stop scrollingif (scrollState == SCROLL_STATE_IDLE) {View itemView = getChildAt(0);if (itemView != null) {/*** Fine tuning*/float deltaY = itemView.getY();if (deltaY == 0) {return;}Log.d(TAG, "WheelListView deltaY=" + deltaY + ""+ ", mItemHeight ==" + mItemHeight);if (Math.abs(deltaY) < mItemHeight / 2) {// not half, scroll backsmoothScrollBy(getDistance(deltaY), 10);} else {// more than half, scroll nextsmoothScrollBy(getDistance(mItemHeight + deltaY), 10);}}}}@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {refreshItems();}});setOnFocusChangeListener(new OnFocusChangeListener() {@Overridepublic void onFocusChange(View v, boolean hasFocus) {if (hasFocus) {invalidate();}}});}private int getDistance(float scrollDistance) {if (Math.abs(scrollDistance) <= 2) {return (int) scrollDistance;} else if (Math.abs(scrollDistance) < 12) {return scrollDistance > 0 ? 2 : -2;} else {return (int) (scrollDistance / 6);}}//used for callbackprivate void refreshItems() {int offset = mWheelSize / 2;int firstPosition = getFirstVisiblePosition();int position = 0;if (getChildAt(0) == null) {return;}if (Math.abs(getChildAt(0).getY()) <= mItemHeight / 2) {position = firstPosition + offset;} else {position = firstPosition + offset + 1;}if (position == mCurrentPositon) {return;}mCurrentPositon = position;if (mItemSelectedListener != null) {handler.sendEmptyMessageDelayed(HANDLER_LISTENER, MIN_TIME);}resetItems(firstPosition, position, offset);}private void resetItems(int firstPosition, int position, int offset) {for (int i = position - offset - 1; i < position + offset + 1; i++) {View itemView = getChildAt(i - firstPosition);if (itemView == null) {continue;}TextView labelTv = (TextView) itemView.findViewById(R.id.type_name);if (position == i) {if (isRecover && getSelection() == 0) {labelTv.setTextColor(mLabelColor);isRecover = false;} else {labelTv.setTextColor(mLabelSelectColor);}labelTv.setTextSize(PLEX_UNIT_PX, 55);itemView.setAlpha(1f);} else {labelTv.setTextColor(mLabelColor);labelTv.setTextSize(PLEX_UNIT_PX, 35);itemView.setAlpha(mAlphaGradual);}}}/*** @return true location*/private int getPosition() {int offset = mWheelSize / 2;if (getChildAt(0) == null) {return 0;}if (Math.abs(getChildAt(0).getY()) <= mItemHeight / 2) {return offset;} else {return offset + 1;}}@Overrideprotected void onMeasure(int arg0, int arg1) {super.onMeasure(arg0, arg1);mItemWidth = getWidth();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (this.isFocused()) {canvas.drawRect(0, mItemHeight * (mWheelSize / 2), mItemWidth,mItemHeight * (mWheelSize / 2 + 1), seletedSolidPaint);}}/*** 焦点变化时,中间选中框字体颜色变化*/@Overrideprotected void onFocusChanged(boolean arg0, int arg1, Rect arg2) {super.onFocusChanged(arg0, arg1, arg2);View itemView = getChildAt(getPosition());TextView labelTv = (TextView) itemView.findViewById(R.id.type_name);if (this.isFocused()) {labelTv.setTextColor(mLabelSelectColor);} else {labelTv.setTextColor(mLabelColor);}}@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {int keyCode = event.getKeyCode();if (event.getAction() == KeyEvent.ACTION_DOWN) {Log.i(TAG, "dispatchKeyEvent() WheelListview ACTION_DOWN===="+ event.getKeyCode());switch (keyCode) {case KeyEvent.KEYCODE_DPAD_DOWN:smoothScrollBy(mItemHeight, 200);proSelection = curSelection;curSelection = getSelection();if (handler.hasMessages(HANDLER_LISTENER)) {handler.removeMessages(HANDLER_LISTENER);} else {if (proSelection == curSelection) {handler.sendEmptyMessage(LAST_HANDLER_LISTENER);}}setSelection(getSelection()); // solve the system bugreturn true;case KeyEvent.KEYCODE_DPAD_UP:smoothScrollBy(-mItemHeight, 200);proSelection = curSelection;curSelection = getSelection();if (handler.hasMessages(HANDLER_LISTENER)) {handler.removeMessages(HANDLER_LISTENER);} else {if (proSelection == curSelection) {handler.sendEmptyMessage(LAST_HANDLER_LISTENER);}}setSelection(getSelection()); // solve the system bugreturn true;default:break;}}return super.dispatchKeyEvent(event);}private Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {switch (msg.what) {case HANDLER_LISTENER:mItemSelectedListener.onItemSelected(getSelection());break;case LAST_HANDLER_LISTENER:mItemSelectedListener.onItemSelected(getSelection());break;default:break;}};};/*** @param mItemSelectedListener*/public void setOnWheelItemSelectedListener(WheelItemSelectedListener mItemSelectedListener) {this.mItemSelectedListener = mItemSelectedListener;}@Overridepublic void setAdapter(ListAdapter adapter) {super.setAdapter(adapter);mDataSize = adapter.getCount() - mWheelSize + 1;initView();}public void setAdapter(ListAdapter adapter, int dataSize) {super.setAdapter(adapter);mDataSize = dataSize;initView();}public void recover() {if (getSelection() == 0) return;smoothScrollToPosition(0);isRecover = true;}public int getSelection() {if (mCurrentPositon == 0) {mCurrentPositon = mWheelSize / 2;}Log.d("TAG", "WheelListView mCurrentPositon ===" + mCurrentPositon);return (mCurrentPositon - mWheelSize / 2) % mDataSize;}/*** @param wheelSize*/public void setWheelSize(int wheelSize) throws WheelListViewException {if (mWheelSize % 2 != 1) {throw new WheelListViewException("wheelSize must be odd number!");}mWheelSize = wheelSize;}public class WheelListViewException extends Exception {private static final long serialVersionUID = 1L;public WheelListViewException(String detailMessage) {super(detailMessage);}}private void initView() {mItemHeight = measureHeight();ViewGroup.LayoutParams lp = getLayoutParams();lp.height = mItemHeight * mWheelSize;}private int measureHeight() {ListAdapter adapter = getAdapter();// 容错if (adapter == null || adapter.getCount() == 0) {return 0;}View itemView = adapter.getView(0, null, this);itemView.measure(0, 0);return itemView.getMeasuredHeight();}/*** * @author puky* @param position* return real listview item position* */public interface WheelItemSelectedListener {public void onItemSelected(int position);}public void setSeletedSolidColor(int color){this.seletedSolidColor = color;seletedSolidPaint.setColor(color);}public void setLabelSelectColor(int color){this.mLabelSelectColor = color;}public void setLabelColor(int color){this.mLabelColor = color;}}

package com.pu.test;import java.util.List;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;public abstract class WheelListAdapter<T> extends BaseAdapter{private int mWheelSize = 3;protected Context context;protected List<T> listData;protected LayoutInflater layoutInflater;public WheelListAdapter(Context context, List<T> listData, int wheelSize) {this.context = context;this.listData = listData;this.mWheelSize = wheelSize;layoutInflater = LayoutInflater.from(context);}@Overridepublic int getCount() {return listData.size() + mWheelSize - 1;}@Overridepublic Object getItem(int position) {if (position < mWheelSize / 2|| position >= listData.size() + mWheelSize / 2) {return null;} else {return listData.get((position - mWheelSize / 2) %listData.size());}}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {Object holder = null;if (convertView == null) {convertView = buildConvertView(layoutInflater);holder = buildHolder(convertView);convertView.setTag(holder);} else {holder = convertView.getTag();}if (position < mWheelSize / 2|| position >= listData.size() + mWheelSize / 2) {invisibleView(holder, convertView);} else {position = (position - mWheelSize / 2) % listData.size();visibleView(holder, convertView, position);}return convertView;}public void setData(List<T> data){this.listData = data;}protected abstract Object buildHolder(View convertView);protected abstract View buildConvertView(LayoutInflater layoutInflater);/*** 条件满足视图不可见时调用*/protected abstract void invisibleView(Object viewHolder, View convertView);/*** 条件满足视图可见时调用* @param position*/protected abstract void visibleView(Object viewHolde, View convertView, int position);}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。