关于RecyclerView的item中TextView跑马灯

今天遇到一个奇怪的问题,不知道大家是否遇到过。关于RecyclerViewitem中的TextView设置跑马灯的问题(Android TV开发)。需要实现的效果是:当我选中RecyclerView的一个item,如果该item中的tvTitle内容长度超出它的宽度,就实现跑马灯效果。问题:当我在RecyclerView中按下键使焦点选中内容长度超过tvTitle宽度(即tvTitle需要滚动的item时),焦点会跑飞(焦点回到页面最初的焦点位置)。

 

一、问题做法

1、首先我是在AdapteronBindViewHolder中给ViewHolder设置Tag。(之前一直这样做,后来也发现不是ViewHolder设置Tag的问题)

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, intposition) {
    ViewHolder viewHolder = (ViewHolder) holder;
    viewHolder.itemView.setTag(viewHolder);    // 做标记ViewHolder

    ...

}

 

2、然后同样在Adapter中写跑马灯的方法。

private View mLastMarqueeView;

// 外面直接调用改方法,传入item即可
public void updateViewMarquee(View view){
    if(mLastMarqueeView!= null) {
        setViewMarquee(mLastMarqueeView, false);
    }
    setViewMarquee(view, true,position);
    mLastMarqueeView= view;
}
private void setViewMarquee(View view, booleanmarquee){
    if(view ==null)
        return;
    ViewHolder holder = (ViewHolder) view.getTag(); // 获取标记ViewHolder
    if(holder !=null && holder.tvTitle!= null){
        if(marquee) {
            holder.tvTitle.setMarqueeRepeatLimit(-1);
            holder.tvTitle.setEllipsize(TextUtils.TruncateAt.MARQUEE);
        }else{
            holder.tvTitle.setMarqueeRepeatLimit(0);
            holder.tvTitle.setEllipsize(TextUtils.TruncateAt.END);
        }
    }
}

 

3、在外面该item获得焦点的地方调用updateViewMarquee(View view)方法,使选中该item后,该item中的tvTitle实现跑马灯效果。

/**
 * 每项item的获取焦点监听(此处为自定义RecyclerViewTV中封装好的接口)
 */
private RecyclerViewTV.OnItemListenermSpecificOnItemListener =new RecyclerViewTV.OnItemListener() {
    @Override
    public voidonItemSelected(RecyclerViewTV parent,View itemView,

int position){
        mOldView= itemView;

        // 当item获取到焦点,让该item的tvTitle实现跑马灯
        mRecSpecAdapter.updateViewMarquee(itemView);
    }
};

 

(当然也可在xml中直接设置android:marqueeRepeatLimit="marquee_forever" android:singleLine="true" android:ellipsize="marquee"实现跑马灯)(问题一样还存在,如果将android:ellipsize="end"不会有焦点跑丢的现象,但是就无法实现跑马灯效果)

 

 

二、发现问题

刚开始一直以为是RecyclerViewitem不能setTag()viewHolder,后来发现问题是RecyclerView中显示了布局的重用,所以当从不需要跑马灯的tvTitle所在的item到需要跑马灯的tvTitleitem时,因为布局的重用。使用RecyclerView丢失的焦点,当然丢失焦点后,该页面的焦点则被页面最起初的控件(可获得焦点的控件)获取到焦点,因此出现我所遇到的情况。

 

三、换方法实现效果

经过反复的调试,不让ViewHolder重用等等的方法都试过了,还是没能解决。最后只能换了另外一种方法实现了项目中需要的效果。大致思路为:AdapteronBindViewHolder()方法中就判断该item中的tvTitle的内容长度是否超出宽度,如果超出,则将ellipsize设置为marquee,不超出的设置为end。这样就有效的避免了RecyclerView布局重用造成的不必要的问题。其中需要方法isOverFlowedTextView tv)来判断内容是否超出宽度。

实现方法如下:

1、 TextView中的xml设置

android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
android:ellipsize="end"

2

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, intposition) {
    ViewHolder viewHolder = (ViewHolder) holder;

tvTitle.setText("《"+m.getTitle()+"》");


    if(isOverFlowed(tvTitle)){
       tvTitle.setMarqueeRepeatLimit(-1);
       tvTitle.setEllipsize(TextUtils.TruncateAt.MARQUEE);
    }else{
       tvTitle.setMarqueeRepeatLimit(0);
       tvTitle.setEllipsize(TextUtils.TruncateAt.END);
    }

}

 

/**
 * 判断TextView的内容宽度是否超出其可用宽度
 *
@paramtv
 *
@return
 
*/
public static boolean isOverFlowed(TextView tv) {
    intavailableWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight();
    Paint textViewPaint = tv.getPaint();
    float textWidth = textViewPaint.measureText(tv.getText().toString());
    if (textWidth > availableWidth) {
        return true;
    }else {
        return false;
    }
}

 

虽然这个不是最佳的实现方法,但是也能达到了预期的效果,规避了原先的问题。至于原先问题,还有待探究。如上有什么问题,欢迎大神们指正;如果有更好的实现方法还望指教!

你可能感兴趣的:(Android,android,RecyclerView,TextView,跑马灯,盒子开发)