吐槽
年前辞了职,年后去香港了玩了几天,然后就开始找工作了,找工作就要面试。笔试有些题看的我一脸蒙蔽,java是基于哪种语言,说实话不记得,pass了,回家突击背书。面试也有恶心的,问了职业发展规划,我说我要转python方向(心想我他妈坑定要坐你的位置啊),又问为什么转python,我说貌似比较火,薪资高,也被pass了,我真是日了狗,真是上层人士不懂底层码农的艰辛。最后还是找到了,新公司开发部的管理也更加的规范,老大是阿里的,感觉有很多东西要学,激情也就瞬间上来了(git真的从没真实用过),公司有自己的oa系统。
回归正题吧,新公司业务主要是电视端。之前也做过,但也是浅尝辄止。主要是recyclerview与焦点的控制
技术点:
1.上面导航栏遥控器切换,下面要刷新数据
2.内容的分类,分页(加载更多),上下滑动的时候导航栏跟着动
3.焦点选中效果
4.导航栏下按的时候,跳到内容的第一个item,同理第一排内容的item上按的时候跳到对应的导航栏
解决方案:
1.用一个recyclerview来做这个页面
a.item的分类:头部+标题+内容
b.合并item
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (position==0||getItemViewType(position)==2){
return 5;
} else {
return 1;
}
}
});
}
这个方法的意思呢,当item是头部或者标题的时候,我将我的5列合成一列,是内容的时候不合并。假设我有一个页面,第一行有2个item,第二行有三个item,第三行有4个item,那么我的girdlayoutmanager设置的spancount应该是2,3,4的最小公倍数12。两列的时候return6,三列的时候return4,四列的时候return3。知道这个加上recyclerview的分类那么剩下的事情就是数据扁平化了。
2。焦点控制。
首先要确定的一点是,遥控器的确定事件就是onclick。其余的就是不要在activity里实现onkeydown方法,这样代码很乱,最好自定义recyclerview。如果不自定义的话,那么从导航栏按下,下个聚焦的不是内容的第一个,而是中间,此时要在recyclerview的dispatchKeyEvent方法处理key_down事件
case KeyEvent.KEYCODE_DPAD_DOWN:
//让第一个默认选中
View lView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_LEFT);
View rView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_RIGHT);
View downView;
if (lView==null&&rView==null){
//焦点左边的view与焦点右边的view都是空的话,说明此事焦点在头部,
// 说明此时是从导航栏按下来,要让第一个item获得焦点
downView= getChildAt(2);//第一个item就是第二个position的位置
}else{
downView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_DOWN);
}
Log.i(TAG, " downView is null:" + (downView == null));
if (downView != null) {
downView.requestFocus();
return true;
} else {
this.smoothScrollBy(0, dy);
return true;
}
从第一排往上按回到指定的导航button的处理
思路:焦点上去的时候不要让导航的button去获取焦点,而是传给导航的linearlayout。也就是三个button不用focus监听,之间用setSelect(true)来切换图片文字。我知道在左右的keydown事件从处理。当然得先知道此时是导航的linearlayout获取焦点。
case KeyEvent.KEYCODE_DPAD_LEFT:
View leftView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_LEFT);
View rightViews = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_RIGHT);
//左右两边都是空说明此事焦点在头部的linearlayout
if (rightViews==null&&leftView==null){
if (getAdapter()!=null){
( (PersonalityGrowthAdapter)getAdapter()).func(-1);
}
}
case KeyEvent.KEYCODE_DPAD_RIGHT:
View rightView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_RIGHT);
View leftViews=FocusFinder.getInstance().findNextFocus(this,focusView,View.FOCUS_LEFT);
if (rightView==null&&leftViews==null){
if (getAdapter()!=null){
( (PersonalityGrowthAdapter)getAdapter()).func(1);
}
}
//用于导航栏左右逻辑
public void func(int dir) {
//当前是否在导航栏上,正数向右,负数向左
Toast.makeText(context,"当前在导航栏上", Toast.LENGTH_SHORT).show();
if (dir > 0) {
if (currentNavIndex >= 0 && currentNavIndex < 2) {
currentNavIndex++;
}
for (int i = 0; i < ll_tbar.getChildCount(); i++) {
ll_tbar.getChildAt(i).setSelected(false);
TextPaint tp = ((TextView) ll_tbar.getChildAt(i)).getPaint();
tp.setFakeBoldText(false);
}
ll_tbar.getChildAt(currentNavIndex).setSelected(true);
TextPaint tp = ((TextView) ll_tbar.getChildAt(currentNavIndex)).getPaint();
tp.setFakeBoldText(true);
}
if (dir < 0) {
if (currentNavIndex > 0 && currentNavIndex <= 2) {
currentNavIndex--;
}
for (int i = 0; i < ll_tbar.getChildCount(); i++) {
ll_tbar.getChildAt(i).setSelected(false);
TextPaint tp = ((TextView) ll_tbar.getChildAt(i)).getPaint();
tp.setFakeBoldText(false);
}
ll_tbar.getChildAt(currentNavIndex).setSelected(true);
TextPaint tp = ((TextView) ll_tbar.getChildAt(currentNavIndex)).getPaint();
tp.setFakeBoldText(true);
}
if (remoteControlListener!=null){
remoteControlListener.changeNav(currentNavIndex);
}
}
3.选中布局的切换,这主要是才用组件的显示与隐藏
holder.itemView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean isfous) {
if (isfous){
mCurrentfocus=position;
Drawable drawable=context.getResources().getDrawable(R.drawable.border_color);
((PGView_ContentHolder)holder).cv_01.setForeground(drawable);
if (!testData01.isFunc()){
((PGView_ContentHolder)holder).tv_content_s.setVisibility(View.VISIBLE);
((PGView_ContentHolder)holder).tv_content.setVisibility(View.GONE);
}
enlargeAnim(view);
}else{
((PGView_ContentHolder)holder).cv_01.setForeground(null);
if (!testData01.isFunc()){
((PGView_ContentHolder)holder).tv_content_s.setVisibility(View.GONE);
((PGView_ContentHolder)holder).tv_content.setVisibility(View.VISIBLE);
}
reduceAnim(view);
}
}
});
4.焦点错乱。一个是遥控器上按与下按由于recyclerview复用导致的焦点错乱。
/**
防止RecyclerView刷新时焦点不错乱bug的步骤如下:
(1)adapter执行setHasStableIds(true)方法
(2)重写getItemId()方法,让每个view都有各自的id
(3)RecyclerView的动画必须去掉
*/
setItemAnimator(null);
@Override
public boolean isInTouchMode() {
// 解决4.4版本抢焦点的问题
if (Build.VERSION.SDK_INT == 19) {
return !(hasFocus() && !super.isInTouchMode());
} else {
return super.isInTouchMode();
}
//return super.isInTouchMode();
}
还有一个是加载更多时候导致的错乱
//加载新一页的数据
public void loadmore(List<TestData01> list,int currentfocus) {
int start=dataList.size()-1;
int length=list.size();
dataList.addAll(list);
mCurrentfocus=currentfocus;
notifyItemRangeChanged(start,length);//处理焦点的错乱
}
5.下按与上按的时候要伴随着recyclerview的滑动
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (mInterceptLister != null && mInterceptLister.onIntercept(event)) {
return true;
}
boolean result = super.dispatchKeyEvent(event);
View focusView = this.getFocusedChild();
currentfocus=getChildPosition(focusView);//把当前的聚焦对象的位置记录下来
Log.d(TAG, "dispatchKeyEvent:--> focusView: "+currentfocus);
if (focusView == null) {
return result;
} else {
int dy = 0;
int dx = 0;
if (getChildCount() > 0) {
View firstView = this.getChildAt(0);
dy = firstView.getHeight();
dx = firstView.getWidth();
}
if (event.getAction() == KeyEvent.ACTION_UP) {
//Log.i(TAG, "遥控器向上按");
// View UPView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_UP);
//
return true;
} else {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_RIGHT:
View rightView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_RIGHT);
View leftViews=FocusFinder.getInstance().findNextFocus(this,focusView,View.FOCUS_LEFT);
if (rightView==null&&leftViews==null){
if (getAdapter()!=null){
( (PersonalityGrowthAdapter)getAdapter()).func(1);
}
}
Log.i(TAG, "rightView is null:" + (rightView == null));
Log.i(TAG, "leftViews is null:" + (leftViews == null));
if (rightView != null) {
rightView.requestFocus();
return true;
} else {
this.smoothScrollBy(dx, 0);
return true;
}
case KeyEvent.KEYCODE_DPAD_LEFT:
View leftView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_LEFT);
View rightViews = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_RIGHT);
//左右两边都是空说明此事焦点在头部的linearlayout
if (rightViews==null&&leftView==null){
if (getAdapter()!=null){
( (PersonalityGrowthAdapter)getAdapter()).func(-1);
}
}
Log.i(TAG, "leftView is null:" + (leftView == null));
if (leftView != null) {
leftView.requestFocus();
return true;
} else {
this.smoothScrollBy(-dx, 0);
return true;
}
case KeyEvent.KEYCODE_DPAD_DOWN:
//让第一个默认选中
View lView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_LEFT);
View rView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_RIGHT);
View downView;
if (lView==null&&rView==null){
//焦点左边的view与焦点右边的view都是空的话,说明此事焦点在头部,
// 说明此时是从导航栏按下来,要让第一个item获得焦点
downView= getChildAt(2);//第一个item就是第二个position的位置
}else{
downView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_DOWN);
}
Log.i(TAG, " downView is null:" + (downView == null));
if (downView != null) {
downView.requestFocus();
return true;
} else {
this.smoothScrollBy(0, dy);
return true;
}
case KeyEvent.KEYCODE_DPAD_UP:
View upView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_UP);
// Log.i(TAG, "upView is null:" + (upView == null));
if (event.getAction() == KeyEvent.ACTION_UP) {
return true;
} else {
if (upView != null) {
this.smoothScrollBy(0, -dy);
upView.requestFocus();
/* View upViews = FocusFinder.getInstance().findNextFocus(this, upView, View.FOCUS_UP);
View rViews = FocusFinder.getInstance().findNextFocus(this, upView, View.FOCUS_RIGHT);
View lViews = FocusFinder.getInstance().findNextFocus(this, upView, View.FOCUS_LEFT);
if (upViews==null&&rViews==null&&lViews==null){
Log.i("FFDDD::","导航");
upView.requestFocus();
smoothScrollToPosition(0);
}else{
Log.i("FFDDD::","不是导航");
Log.i(TAG, "upView is null:" + (upView == null)+dy);
this.smoothScrollBy(0, -dy);
upView.requestFocus();
}*/
return true;
} else {
Log.i("FFDDD::","顶部view为空");
LayoutManager layoutManager = getLayoutManager();
int childLayoutPosition = getChildLayoutPosition(focusView);
if (layoutManager instanceof GridLayoutManager) {
int spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
if (childLayoutPosition <= spanCount) {
return result;
}
} else if (layoutManager instanceof LinearLayoutManager) {
if (childLayoutPosition == 0) {
return result;
}
}
this.smoothScrollBy(0, -dy);
return true;
}
}
}
}
}
return result;
}
还有就是细节问题了,间距之类的,这个就不谈了
附件:
自定义recyclerview
package com.familybox.ui.family.widget.thrid_party;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Rect;
import android.os.Build;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.FocusFinder;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import com.familybox.R;
import com.familybox.ui.demo.PersonalityGrowthAdapter;
/**
* Created by hcy.
*/
public class TvRecyclerView extends RecyclerView {
private static final String TAG = "TvRecyclerView";
private int position;
//焦点是否居中
private boolean mSelectedItemCentered;
private int mSelectedItemOffsetStart;
private int mSelectedItemOffsetEnd;
//分页的时候使用
private int mLoadMoreBeforehandCount = 0;
//记录当前的focus的位置
private int currentfocus=0;
public TvRecyclerView(Context context) {
this(context, null);
}
public TvRecyclerView(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public TvRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
initView();
initAttr(context, attrs);
}
private void initView() {
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setHasFixedSize(true);
setWillNotDraw(true);
setOverScrollMode(View.OVER_SCROLL_NEVER);
setChildrenDrawingOrderEnabled(true);
setClipChildren(false);
setClipToPadding(false);
setClickable(false);
setFocusable(true);
setFocusableInTouchMode(true);
/**
防止RecyclerView刷新时焦点不错乱bug的步骤如下:
(1)adapter执行setHasStableIds(true)方法
(2)重写getItemId()方法,让每个view都有各自的id
(3)RecyclerView的动画必须去掉
*/
setItemAnimator(null);
}
private void initAttr(Context context, AttributeSet attrs) {
if (attrs != null) {
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.TvRecyclerView);
/**
* 如果是towWayView的layoutManager
*/
final String name = a.getString(R.styleable.TvRecyclerView_tv_layoutManager);
mSelectedItemCentered = a.getBoolean(R.styleable.TvRecyclerView_tv_selectedItemCentered, false);
mLoadMoreBeforehandCount = a.getInteger(R.styleable.TvRecyclerView_tv_loadMoreBeforehandCount, 0);
mSelectedItemOffsetStart = a.getDimensionPixelSize(R.styleable.TvRecyclerView_tv_selectedItemOffsetStart, 0);
mSelectedItemOffsetEnd = a.getDimensionPixelSize(R.styleable.TvRecyclerView_tv_selectedItemOffsetEnd, 0);
a.recycle();
}
}
private int getFreeWidth() {
return getWidth() - getPaddingLeft() - getPaddingRight();
}
private int getFreeHeight() {
return getHeight() - getPaddingTop() - getPaddingBottom();
}
@Override
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
}
@Override
public boolean hasFocus() {
return super.hasFocus();
}
@Override
public boolean isInTouchMode() {
// 解决4.4版本抢焦点的问题
if (Build.VERSION.SDK_INT == 19) {
return !(hasFocus() && !super.isInTouchMode());
} else {
return super.isInTouchMode();
}
//return super.isInTouchMode();
}
@Override
public void requestChildFocus(View child, View focused) {
if (null != child) {
if (mSelectedItemCentered) {
mSelectedItemOffsetStart = !isVertical() ? (getFreeWidth() - child.getWidth()) : (getFreeHeight() - child.getHeight());
mSelectedItemOffsetStart /= 2;
mSelectedItemOffsetEnd = mSelectedItemOffsetStart;
}
}
super.requestChildFocus(child, focused);
}
@Override
public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) {
final int parentLeft = getPaddingLeft();
final int parentRight = getWidth() - getPaddingRight();
final int parentTop = getPaddingTop();
final int parentBottom = getHeight() - getPaddingBottom();
final int childLeft = child.getLeft() + rect.left;
final int childTop = child.getTop() + rect.top;
final int childRight = childLeft + rect.width();
final int childBottom = childTop + rect.height();
final int offScreenLeft = Math.min(0, childLeft - parentLeft - mSelectedItemOffsetStart);
final int offScreenRight = Math.max(0, childRight - parentRight + mSelectedItemOffsetEnd);
final int offScreenTop = Math.min(0, childTop - parentTop - mSelectedItemOffsetStart);
final int offScreenBottom = Math.max(0, childBottom - parentBottom + mSelectedItemOffsetEnd);
final boolean canScrollHorizontal = getLayoutManager().canScrollHorizontally();
final boolean canScrollVertical = getLayoutManager().canScrollVertically();
// Favor the "start" layout direction over the end when bringing one side or the other
// of a large rect into view. If we decide to bring in end because start is already
// visible, limit the scroll such that start won't go out of bounds.
final int dx;
if (canScrollHorizontal) {
if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
dx = offScreenRight != 0 ? offScreenRight
: Math.max(offScreenLeft, childRight - parentRight);
} else {
dx = offScreenLeft != 0 ? offScreenLeft
: Math.min(childLeft - parentLeft, offScreenRight);
}
} else {
dx = 0;
}
// Favor bringing the top into view over the bottom. If top is already visible and
// we should scroll to make bottom visible, make sure top does not go out of bounds.
final int dy;
if (canScrollVertical) {
dy = offScreenTop != 0 ? offScreenTop : Math.min(childTop - parentTop, offScreenBottom);
} else {
dy = 0;
}
if (dx != 0 || dy != 0) {
if (immediate) {
scrollBy(dx, dy);
} else {
smoothScrollBy(dx, dy);
}
// 重绘是为了选中item置顶,具体请参考getChildDrawingOrder方法
postInvalidate();
return true;
}
return false;
}
@Override
public int getBaseline() {
return -1;
}
public int getSelectedItemOffsetStart() {
return mSelectedItemOffsetStart;
}
public int getSelectedItemOffsetEnd() {
return mSelectedItemOffsetEnd;
}
@Override
public void setLayoutManager(LayoutManager layout) {
super.setLayoutManager(layout);
}
/**
* 判断是垂直,还是横向.
*/
private boolean isVertical() {
LayoutManager manager = getLayoutManager();
if (manager != null) {
LinearLayoutManager layout = (LinearLayoutManager) getLayoutManager();
return layout.getOrientation() == LinearLayoutManager.VERTICAL;
}
return false;
}
/**
* 设置选中的Item距离开始或结束的偏移量;
* 与滚动方向有关;
* 与setSelectedItemAtCentered()方法二选一
*
* @param offsetStart
* @param offsetEnd 从结尾到你移动的位置.
*/
public void setSelectedItemOffset(int offsetStart, int offsetEnd) {
setSelectedItemAtCentered(false);
mSelectedItemOffsetStart = offsetStart;
mSelectedItemOffsetEnd = offsetEnd;
}
/**
* 设置选中的Item居中;
* 与setSelectedItemOffset()方法二选一
*
* @param isCentered
*/
public void setSelectedItemAtCentered(boolean isCentered) {
this.mSelectedItemCentered = isCentered;
}
@Override
protected int getChildDrawingOrder(int childCount, int i) {
View view = getFocusedChild();
if (null != view) {
position = getChildAdapterPosition(view) - getFirstVisiblePosition();
if (position < 0) {
return i;
} else {
if (i == childCount - 1) {//这是最后一个需要刷新的item
if (position > i) {
position = i;
}
return position;
}
if (i == position) {//这是原本要在最后一个刷新的item
return childCount - 1;
}
}
}
return i;
}
public int getFirstVisiblePosition() {
if (getChildCount() == 0)
return 0;
else
return getChildAdapterPosition(getChildAt(0));
}
public int getLastVisiblePosition() {
final int childCount = getChildCount();
if (childCount == 0)
return 0;
else
return getChildAdapterPosition(getChildAt(childCount - 1));
}
/***********
* 按键加载更多 start
**********/
private OnLoadMoreListener mOnLoadMoreListener;
public interface OnLoadMoreListener {
void onLoadMore(int currentfocus);
}
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
this.mOnLoadMoreListener = onLoadMoreListener;
}
protected OnInterceptListener mInterceptLister;
public void setOnInterceptListener(OnInterceptListener listener) {
this.mInterceptLister = listener;
}
/**
* 设置为0,这样可以防止View获取焦点的时候,ScrollView自动滚动到焦点View的位置
*/
protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
return 0;
}
@Override
public void onScrollStateChanged(int state) {
if (state == SCROLL_STATE_IDLE) {
// 加载更多回调,个人认为要保存一下上次焦点的位置
if (null != mOnLoadMoreListener) {
if (getLastVisiblePosition() >= getAdapter().getItemCount() - (1 + mLoadMoreBeforehandCount)) {
mOnLoadMoreListener.onLoadMore(currentfocus);
}
}
}
super.onScrollStateChanged(state);
}
/**
* 子类如果要重写dispatchKeyEvent的话请调用个
* @param event
* @return
*/
protected boolean customDispatchKeyEvent(KeyEvent event){
return super.dispatchKeyEvent(event);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (mInterceptLister != null && mInterceptLister.onIntercept(event)) {
return true;
}
boolean result = super.dispatchKeyEvent(event);
View focusView = this.getFocusedChild();
currentfocus=getChildPosition(focusView);//把当前的聚焦对象的位置记录下来
Log.d(TAG, "dispatchKeyEvent:--> focusView: "+currentfocus);
if (focusView == null) {
return result;
} else {
int dy = 0;
int dx = 0;
if (getChildCount() > 0) {
View firstView = this.getChildAt(0);
dy = firstView.getHeight();
dx = firstView.getWidth();
}
if (event.getAction() == KeyEvent.ACTION_UP) {
//Log.i(TAG, "遥控器向上按");
// View UPView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_UP);
//
return true;
} else {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_RIGHT:
View rightView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_RIGHT);
View leftViews=FocusFinder.getInstance().findNextFocus(this,focusView,View.FOCUS_LEFT);
if (rightView==null&&leftViews==null){
if (getAdapter()!=null){
( (PersonalityGrowthAdapter)getAdapter()).func(1);
}
}
Log.i(TAG, "rightView is null:" + (rightView == null));
Log.i(TAG, "leftViews is null:" + (leftViews == null));
if (rightView != null) {
rightView.requestFocus();
return true;
} else {
this.smoothScrollBy(dx, 0);
return true;
}
case KeyEvent.KEYCODE_DPAD_LEFT:
View leftView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_LEFT);
View rightViews = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_RIGHT);
//左右两边都是空说明此事焦点在头部的linearlayout
if (rightViews==null&&leftView==null){
if (getAdapter()!=null){
( (PersonalityGrowthAdapter)getAdapter()).func(-1);
}
}
Log.i(TAG, "leftView is null:" + (leftView == null));
if (leftView != null) {
leftView.requestFocus();
return true;
} else {
this.smoothScrollBy(-dx, 0);
return true;
}
case KeyEvent.KEYCODE_DPAD_DOWN:
//让第一个默认选中
View lView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_LEFT);
View rView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_RIGHT);
View downView;
if (lView==null&&rView==null){
//焦点左边的view与焦点右边的view都是空的话,说明此事焦点在头部,
// 说明此时是从导航栏按下来,要让第一个item获得焦点
downView= getChildAt(2);//第一个item就是第二个position的位置
}else{
downView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_DOWN);
}
Log.i(TAG, " downView is null:" + (downView == null));
if (downView != null) {
downView.requestFocus();
return true;
} else {
this.smoothScrollBy(0, dy);
return true;
}
case KeyEvent.KEYCODE_DPAD_UP:
View upView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_UP);
// Log.i(TAG, "upView is null:" + (upView == null));
if (event.getAction() == KeyEvent.ACTION_UP) {
return true;
} else {
if (upView != null) {
this.smoothScrollBy(0, -dy);
upView.requestFocus();
/* View upViews = FocusFinder.getInstance().findNextFocus(this, upView, View.FOCUS_UP);
View rViews = FocusFinder.getInstance().findNextFocus(this, upView, View.FOCUS_RIGHT);
View lViews = FocusFinder.getInstance().findNextFocus(this, upView, View.FOCUS_LEFT);
if (upViews==null&&rViews==null&&lViews==null){
Log.i("FFDDD::","导航");
upView.requestFocus();
smoothScrollToPosition(0);
}else{
Log.i("FFDDD::","不是导航");
Log.i(TAG, "upView is null:" + (upView == null)+dy);
this.smoothScrollBy(0, -dy);
upView.requestFocus();
}*/
return true;
} else {
Log.i("FFDDD::","顶部view为空");
LayoutManager layoutManager = getLayoutManager();
int childLayoutPosition = getChildLayoutPosition(focusView);
if (layoutManager instanceof GridLayoutManager) {
int spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
if (childLayoutPosition <= spanCount) {
return result;
}
} else if (layoutManager instanceof LinearLayoutManager) {
if (childLayoutPosition == 0) {
return result;
}
}
this.smoothScrollBy(0, -dy);
return true;
}
}
}
}
}
return result;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
return super.onInterceptTouchEvent(e);
}
/**
* 设置默认选中.
*/
public void setSelectedPosition(int pos) {
this.smoothScrollToPosition(pos);
}
//防止Activity时,RecyclerView崩溃
@Override
protected void onDetachedFromWindow() {
if (getLayoutManager() != null) {
super.onDetachedFromWindow();
}
}
/**
* 是否是最右边的item,如果是竖向,表示右边,如果是横向表示下边
*
* @param childPosition
* @return
*/
public boolean isRightEdge(int childPosition) {
LayoutManager layoutManager = getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
GridLayoutManager.SpanSizeLookup spanSizeLookUp = gridLayoutManager.getSpanSizeLookup();
int totalSpanCount = gridLayoutManager.getSpanCount();
int totalItemCount = gridLayoutManager.getItemCount();
int childSpanCount = 0;
for (int i = 0; i <= childPosition; i++) {
childSpanCount += spanSizeLookUp.getSpanSize(i);
}
if (isVertical()) {
if (childSpanCount % gridLayoutManager.getSpanCount() == 0) {
return true;
}
} else {
int lastColumnSize = totalItemCount % totalSpanCount;
if (lastColumnSize == 0) {
lastColumnSize = totalSpanCount;
}
if (childSpanCount > totalItemCount - lastColumnSize) {
return true;
}
}
} else if (layoutManager instanceof LinearLayoutManager) {
if (isVertical()) {
return true;
} else {
return childPosition == getLayoutManager().getItemCount() - 1;
}
}
return false;
}
/**
* 是否是最左边的item,如果是竖向,表示左方,如果是横向,表示上边
*
* @param childPosition
* @return
*/
public boolean isLeftEdge(int childPosition) {
LayoutManager layoutManager = getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
GridLayoutManager.SpanSizeLookup spanSizeLookUp = gridLayoutManager.getSpanSizeLookup();
int totalSpanCount = gridLayoutManager.getSpanCount();
int childSpanCount = 0;
for (int i = 0; i <= childPosition; i++) {
childSpanCount += spanSizeLookUp.getSpanSize(i);
}
if (isVertical()) {
if (childSpanCount % gridLayoutManager.getSpanCount() == 1) {
return true;
}
} else {
if (childSpanCount <= totalSpanCount) {
return true;
}
}
} else if (layoutManager instanceof LinearLayoutManager) {
if (isVertical()) {
return true;
} else {
return childPosition == 0;
}
}
return false;
}
/**
* 是否是最上边的item,以recyclerview的方向做参考
*
* @param childPosition
* @return
*/
public boolean isTopEdge(int childPosition) {
LayoutManager layoutManager = getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
GridLayoutManager.SpanSizeLookup spanSizeLookUp = gridLayoutManager.getSpanSizeLookup();
int totalSpanCount = gridLayoutManager.getSpanCount();
int childSpanCount = 0;
for (int i = 0; i <= childPosition; i++) {
childSpanCount += spanSizeLookUp.getSpanSize(i);
}
if (isVertical()) {
if (childSpanCount <= totalSpanCount) {
return true;
}
} else {
if (childSpanCount % totalSpanCount == 1) {
return true;
}
}
} else if (layoutManager instanceof LinearLayoutManager) {
if (isVertical()) {
return childPosition == 0;
} else {
return true;
}
}
return false;
}
/**
* 是否是最下边的item,以recyclerview的方向做参考
*
* @param childPosition
* @return
*/
public boolean isBottomEdge(int childPosition) {
LayoutManager layoutManager = getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
GridLayoutManager.SpanSizeLookup spanSizeLookUp = gridLayoutManager.getSpanSizeLookup();
int itemCount = gridLayoutManager.getItemCount();
int childSpanCount = 0;
int totalSpanCount = gridLayoutManager.getSpanCount();
for (int i = 0; i <= childPosition; i++) {
childSpanCount += spanSizeLookUp.getSpanSize(i);
}
if (isVertical()) {
//最后一行item的个数
int lastRowCount = itemCount % totalSpanCount;
if (lastRowCount == 0) {
lastRowCount = gridLayoutManager.getSpanCount();
}
if (childSpanCount > itemCount - lastRowCount) {
return true;
}
} else {
if (childSpanCount % totalSpanCount == 0) {
return true;
}
}
} else if (layoutManager instanceof LinearLayoutManager) {
if (isVertical()) {
return childPosition == getLayoutManager().getItemCount() - 1;
} else {
return true;
}
}
return false;
}
}
activity
package com.familybox.ui.baby.personality_growth;
import android.support.v7.widget.GridLayoutManager;
import android.widget.Toast;
import com.familybox.R;
import com.familybox.ui.BaseActivity;
import com.familybox.ui.demo.PGRecyclerViewItemDecoration;
import com.familybox.ui.demo.PersonalityGrowthAdapter;
import com.familybox.ui.demo.TestData01;
import com.familybox.ui.family.widget.thrid_party.TvRecyclerView;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
/**
* Created by hcy on 2018/4/11.
* 个性成长
* func:家长订阅的取消订阅的功能
*
*/
public class PersonalityGrowthActivity extends BaseActivity{
@BindView(R.id.rv_main)
TvRecyclerView rv_main;
GridLayoutManager gridLayoutManager;
private static final String TAG="PGActivity:::";
private PersonalityGrowthAdapter adapter;
@Override
protected int setLayoutId() {
return R.layout.activty_personality_growth;
}
@Override
protected void init() {
initUI();
initData();
}
@Override
protected void requestInitFocus() {
}
private void initData() {
//数据模拟
List<TestData01> list=new ArrayList<TestData01>();
list.add(new TestData01(3,false,"","",false,"",""));//头部
list.add(new TestData01(0,false,"《我上幼儿园啦》主题节目推荐","",false,"",""));
list.add(new TestData01(1,false,"运营标题X","",false,"《我上幼儿园啦》主题节目推荐",""));
list.add(new TestData01(1,false,"运营标题2","",false,"《我上幼儿园啦》主题节目推荐",""));
list.add(new TestData01(1,false,"运营标题3","",false,"《我上幼儿园啦》主题节目推荐",""));
list.add(new TestData01(1,false,"运营标题5","",false,"《我上幼儿园啦》主题节目推荐",""));
list.add(new TestData01(1,false,"运营标题5","",false,"《我上幼儿园啦》主题节目推荐",""));
list.add(new TestData01(1,false,"运营标题1","",false,"《我上幼儿园啦》主题节目推荐",""));
list.add(new TestData01(1,false,"运营标题2","",false,"《我上幼儿园啦》主题节目推荐",""));
list.add(new TestData01(1,false,"运营标题3","",false,"《我上幼儿园啦》主题节目推荐",""));
list.add(new TestData01(1,false,"运营标题5","",false,"《我上幼儿园啦》主题节目推荐",""));
list.add(new TestData01(1,false,"运营标题5","",false,"《我上幼儿园啦》主题节目推荐",""));
list.add(new TestData01(1,false,"运营标题5","",true,"","《我上幼儿园啦》主题节目推荐"));
/* list.add(new TestData01(0,false,"《奇妙的我》主题节目推荐","",false));
list.add(new TestData01(1,false,"运营标题1","",false));
list.add(new TestData01(1,false,"运营标题2","",false));
list.add(new TestData01(1,false,"运营标题3","",false));
list.add(new TestData01(1,false,"运营标题5","",false));
list.add(new TestData01(1,false,"运营标题5","",false));
list.add(new TestData01(1,false,"运营标题1","",false));
list.add(new TestData01(1,false,"运营标题2","",false));
list.add(new TestData01(1,false,"运营标题3","",false));
list.add(new TestData01(1,false,"运营标题5","",false));
list.add(new TestData01(1,false,"运营标题5","",false));
list.add(new TestData01(0,false,"家长订阅关于《小气》的节目推荐","",false));
list.add(new TestData01(1,false,"运营标题1","",false));
list.add(new TestData01(1,false,"运营标题2","",false));
list.add(new TestData01(1,false,"运营标题3","",false));
list.add(new TestData01(1,false,"运营标题5","",false));
list.add(new TestData01(1,false,"运营标题5","",false));
list.add(new TestData01(1,false,"运营标题1","",false));
list.add(new TestData01(1,false,"运营标题2","",false));
list.add(new TestData01(1,false,"运营标题3","",false));
list.add(new TestData01(1,false,"运营标题5","",false));
list.add(new TestData01(1,false,"运营标题5","",false));*/
if (adapter!=null){
adapter.setData(list);
}
adapter.setRemoteControlListener(new PersonalityGrowthAdapter.onRemoteControlListener() {
@Override
public void makeSure(int navPosition, int currentItemFocusPostion) {
Toast.makeText(PersonalityGrowthActivity.this,"当前遥控器选择了"+navPosition+"?"+currentItemFocusPostion,Toast.LENGTH_SHORT).show();
}
@Override
public void changeNav(int navPosition) {
Toast.makeText(PersonalityGrowthActivity.this,"当行切换了"+navPosition,Toast.LENGTH_SHORT).show();
}
@Override
public void cancelSubscribe(String title) {
if (adapter!=null){
adapter.cancelSubscribe(title);
}
Toast.makeText(PersonalityGrowthActivity.this,"取消订阅按钮启动",Toast.LENGTH_SHORT).show();
}
});
rv_main.setOnLoadMoreListener(new TvRecyclerView.OnLoadMoreListener() {
@Override
public void onLoadMore(int currentfocus) {
Toast.makeText(PersonalityGrowthActivity.this,"加载更多"+currentfocus,Toast.LENGTH_SHORT).show();
List<TestData01> list=new ArrayList<TestData01>();
list.add(new TestData01(0,false,"新一页数据","",false,"",""));
list.add(new TestData01(1,false,"运营标题1","",false,"新一页数据",""));
list.add(new TestData01(1,false,"运营标题2","",false,"新一页数据",""));
list.add(new TestData01(1,false,"运营标题3","",false,"新一页数据",""));
list.add(new TestData01(1,false,"运营标题5","",false,"新一页数据",""));
list.add(new TestData01(1,false,"运营标题5","",false,"新一页数据",""));
list.add(new TestData01(1,false,"运营标题1","",false,"新一页数据",""));
list.add(new TestData01(1,false,"运营标题2","",false,"新一页数据",""));
list.add(new TestData01(1,false,"运营标题3","",false,"新一页数据",""));
list.add(new TestData01(1,false,"运营标题5","",false,"新一页数据",""));
list.add(new TestData01(1,false,"运营标题5","",false,"新一页数据",""));
if (adapter!=null){
adapter.loadmore(list,currentfocus);
}
}
});
}
private void initUI() {
adapter=new PersonalityGrowthAdapter(PersonalityGrowthActivity.this);
gridLayoutManager = new GridLayoutManager(PersonalityGrowthActivity.this, 5);
rv_main.setLayoutManager(gridLayoutManager);
rv_main.setHasFixedSize(true);
//设置item间距
rv_main.addItemDecoration(new PGRecyclerViewItemDecoration(PersonalityGrowthActivity.this));
rv_main.setAdapter(adapter);
adapter.onAttachedToRecyclerView(rv_main);
/* adapter.setListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean isfous) {
if (isfous){
if (adapter!=null){
if (view.getTag()!=null){
view.findViewById(R.id.rl_select).setVisibility(View.VISIBLE);
view.findViewById(R.id.rl_unselect).setVisibility(View.GONE);
}
}
enlargeAnim(view);
}else{
reduceAnim(view);
if (adapter!=null){
if (view.getTag()!=null){
view.findViewById(R.id.rl_unselect).setVisibility(View.VISIBLE);
view.findViewById(R.id.rl_select).setVisibility(View.GONE);
}
}
}
}
});*/
}
}
适配器
package com.familybox.ui.demo;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.CardView;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextPaint;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.familybox.R;
import java.util.ArrayList;
import java.util.List;
/**
* Created by hcy on 2018/4/11.
* func:个性成长详情页的适配器
*/
public class PersonalityGrowthAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
//定义数据
private List<TestData01> dataList;
//上下文
private Context context;
private LayoutInflater inflater;
//recyclerview的分类
//头部
private static final int TYPE_HEAD = 1;
//标题
private static final int TYPE_TITLE = 2;
//内容
private static final int TYPE_CONTENT = 3;
private View.OnFocusChangeListener listener;//焦点变化监听
public void setListener(View.OnFocusChangeListener listener) {
this.listener = listener;
}
public void cancelSubscribe(String title) {
List<TestData01> readyToDeleteList=new ArrayList<TestData01>();
for (int i = 0; i < dataList.size(); i++) {
if (dataList.get(i).getDelete_title().equals(title)||dataList.get(i).getConnect_title().equals(title)||dataList.get(i).getText().equals(title)){
readyToDeleteList.add(dataList.get(i));
}
}
dataList.removeAll(readyToDeleteList);
notifyDataSetChanged();
}
public interface onRemoteControlListener{
//遥控器确定操作
void makeSure(int navPosition,int currentItemFocusPostion);
//切换导航
void changeNav(int navPosition);
//取消订阅
void cancelSubscribe(String title);
}
private onRemoteControlListener remoteControlListener;
public void setRemoteControlListener(onRemoteControlListener remoteControlListener) {
this.remoteControlListener = remoteControlListener;
}
@Override
public int getItemViewType(int position) {
TestData01 testData01 = dataList.get(position);
if (testData01.getType() == 0) {
return TYPE_TITLE;
} else if (testData01.getType() == 1) {
return TYPE_CONTENT;
} else if (testData01.getType() == 3) {
return TYPE_HEAD;
}
return super.getItemViewType(position);
}
private LinearLayout ll_tbar;
private int currentNavIndex = 0;
//用于导航栏左右逻辑
public void func(int dir) {
//当前是否在导航栏上,正数向右,负数向左
Toast.makeText(context,"当前在导航栏上", Toast.LENGTH_SHORT).show();
if (dir > 0) {
if (currentNavIndex >= 0 && currentNavIndex < 2) {
currentNavIndex++;
}
for (int i = 0; i < ll_tbar.getChildCount(); i++) {
ll_tbar.getChildAt(i).setSelected(false);
TextPaint tp = ((TextView) ll_tbar.getChildAt(i)).getPaint();
tp.setFakeBoldText(false);
}
ll_tbar.getChildAt(currentNavIndex).setSelected(true);
TextPaint tp = ((TextView) ll_tbar.getChildAt(currentNavIndex)).getPaint();
tp.setFakeBoldText(true);
}
if (dir < 0) {
if (currentNavIndex > 0 && currentNavIndex <= 2) {
currentNavIndex--;
}
for (int i = 0; i < ll_tbar.getChildCount(); i++) {
ll_tbar.getChildAt(i).setSelected(false);
TextPaint tp = ((TextView) ll_tbar.getChildAt(i)).getPaint();
tp.setFakeBoldText(false);
}
ll_tbar.getChildAt(currentNavIndex).setSelected(true);
TextPaint tp = ((TextView) ll_tbar.getChildAt(currentNavIndex)).getPaint();
tp.setFakeBoldText(true);
}
if (remoteControlListener!=null){
remoteControlListener.changeNav(currentNavIndex);
}
}
public PersonalityGrowthAdapter(Context context) {
dataList = new ArrayList<TestData01>();
this.context = context;
inflater = LayoutInflater.from(context);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEAD) {
return new PGView_HeadHolder(inflater.inflate(R.layout.item_personality_growth_adapter_head, parent, false));
} else if (viewType == TYPE_TITLE) {
return new PGView_TitleHolder(inflater.inflate(R.layout.item_personality_growth_adapter_title, parent, false));
} else if (viewType == TYPE_CONTENT) {
return new PGView_ContentHolder(inflater.inflate(R.layout.item_personality_growth_adapter_content, parent, false));
}
return null;
}
@Override
public void onAttachedToRecyclerView(final RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
/*
* else if (position>12&&position<23){
//((GridLayoutManager)recyclerView.getLayoutManager()).setSpanCount(4);
return 4;
}*/
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
if (position==0||getItemViewType(position)==2){
return 5;
} else {
return 1;
}
}
});
}
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final TestData01 testData01 = dataList.get(position);
/* if (position == mCurrentfocus) {
holder.itemView.requestFocus();
}*/
switch (getItemViewType(position)){
case TYPE_HEAD:
((PGView_HeadHolder)holder).ll_tool.setTag(position);
break;
case TYPE_TITLE:
((PGView_TitleHolder)holder).itemView.setFocusable(false);
((PGView_TitleHolder)holder).tv_title.setText(testData01.getText()+"?"+position);
break;
case TYPE_CONTENT:
holder.itemView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean isfous) {
if (isfous){
mCurrentfocus=position;
Drawable drawable=context.getResources().getDrawable(R.drawable.border_color);
((PGView_ContentHolder)holder).cv_01.setForeground(drawable);
if (!testData01.isFunc()){
((PGView_ContentHolder)holder).tv_content_s.setVisibility(View.VISIBLE);
((PGView_ContentHolder)holder).tv_content.setVisibility(View.GONE);
}
enlargeAnim(view);
}else{
((PGView_ContentHolder)holder).cv_01.setForeground(null);
if (!testData01.isFunc()){
((PGView_ContentHolder)holder).tv_content_s.setVisibility(View.GONE);
((PGView_ContentHolder)holder).tv_content.setVisibility(View.VISIBLE);
}
reduceAnim(view);
}
}
});
if (testData01.isFunc()){
//取消订阅按钮
//((PGView_ContentHolder)holder).cv_01.setForeground(drawable);
((PGView_ContentHolder)holder).tv_content_s.setVisibility(View.GONE);
((PGView_ContentHolder)holder).tv_content.setVisibility(View.GONE);
if (remoteControlListener!=null){
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//遥控器取消订阅处理
remoteControlListener.cancelSubscribe(testData01.getDelete_title());
}
});
}
}else{
((PGView_ContentHolder)holder).tv_content_s.setVisibility(View.GONE);
((PGView_ContentHolder)holder).tv_content.setVisibility(View.VISIBLE);
if (remoteControlListener!=null){
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//遥控器确定按钮
remoteControlListener.makeSure(currentNavIndex,mCurrentfocus);
}
});
}
}
if (((PGView_ContentHolder)holder).itemView.getTag()==null){
((PGView_ContentHolder)holder).itemView.setTag(position);
}
((PGView_ContentHolder)holder).tv_content_s.setText(testData01.getText()+"/"+position);
((PGView_ContentHolder)holder).tv_content.setText(testData01.getText()+"/"+position);
break;
}
}
private int mCurrentfocus=0;
@Override
public int getItemCount() {
return dataList.size(); //数据源(头部布局是死的)
}
public void setData(List<TestData01> list) {
dataList.addAll(list);
notifyDataSetChanged();
}
//加载新一页的数据
public void loadmore(List<TestData01> list,int currentfocus) {
int start=dataList.size()-1;
int length=list.size();
dataList.addAll(list);
mCurrentfocus=currentfocus;
notifyItemRangeChanged(start,length);//处理焦点的错乱
}
public class PGView_HeadHolder extends RecyclerView.ViewHolder{
private LinearLayout ll_tool;
public PGView_HeadHolder( View itemView) {
super(itemView);
ll_tool=itemView.findViewById(R.id.ll_tool);
ll_tool.setTag(-1);
ll_tool.getChildAt(0).setSelected(true);
//字体加粗
TextPaint tp = ((TextView) ll_tool.getChildAt(0)).getPaint();
tp.setFakeBoldText(true);
currentNavIndex=0;
ll_tbar=ll_tool;
}
}
public class PGView_TitleHolder extends RecyclerView.ViewHolder{
private TextView tv_title;
public PGView_TitleHolder( View itemView) {
super(itemView);
itemView.setFocusable(false);
tv_title=(TextView)itemView.findViewById(R.id.tv_title);
}
}
public class PGView_ContentHolder extends RecyclerView.ViewHolder{
private TextView tv_content;
//private RelativeLayout rl_unselect;
// private RelativeLayout rl_select;
private TextView tv_content_s;
private CardView cv_01;
public PGView_ContentHolder(View itemView) {
super(itemView);
itemView.setFocusable(true);
tv_content=(TextView) itemView.findViewById(R.id.tv_content);
// rl_unselect=itemView.findViewById(R.id.rl_unselect);
// rl_select=itemView.findViewById(R.id.rl_select);
tv_content_s= itemView.findViewById(R.id.tv_content_s);
cv_01=itemView.findViewById(R.id.cv_01);
}
}
//获取焦点view实现放大效果
private void enlargeAnim(View view) {
if (Build.VERSION.SDK_INT >= 21) {//android 5.0以上
ViewCompat.animate(view).scaleX(1.13f).scaleY(1.13f).translationZ(1.13f).start();
} else {
Animation a = android.view.animation.AnimationUtils.loadAnimation(view.getContext(), R.anim.uikit_enlarge);
a.setFillAfter(true);
view.clearAnimation();
view.setAnimation(a);
view.bringToFront();
a.start();
}
}
//失去焦点view实现缩小效果
private void reduceAnim(View view) {
if (Build.VERSION.SDK_INT >= 21) {//android 5.0以上
ViewCompat.animate(view).scaleX(1.0f).scaleY(1.0f).translationZ(1.0f).start();
} else {
Animation a = android.view.animation.AnimationUtils.loadAnimation(view.getContext(), R.anim.uikit_reduce);
a.setFillAfter(true);
view.clearAnimation();
view.startAnimation(a);
a.start();
}
}
/* holder.itemView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean isfous) {
if (isfous){
mCurrentfocus=position;
Drawable drawable=context.getResources().getDrawable(R.drawable.border_color);
((PGView_ContentHolder)holder).cv_01.setForeground(drawable);
((PGView_ContentHolder)holder).tv_content_s.setVisibility(View.VISIBLE);
((PGView_ContentHolder)holder).tv_content.setVisibility(View.GONE);
enlargeAnim(view);
}else{
((PGView_ContentHolder)holder).cv_01.setForeground(null);
((PGView_ContentHolder)holder).tv_content_s.setVisibility(View.GONE);
((PGView_ContentHolder)holder).tv_content.setVisibility(View.VISIBLE);
reduceAnim(view);
}
}
});*/
}
间距
package com.familybox.ui.demo;
import android.content.Context;
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import com.familybox.utils.PxtransformUtil;
/**
* Created by hcy on 2018/4/12.
*/
public class PGRecyclerViewItemDecoration extends RecyclerView.ItemDecoration{
/**
* Retrieve any offsets for the given item. Each field of <code>outRect</code> specifies
* the number of pixels that the item view should be inset by, similar to padding or margin.
* The default implementation sets the bounds of outRect to 0 and returns.
* <p>
* <p>
* If this ItemDecoration does not affect the positioning of item views, it should set
* all four fields of <code>outRect</code> (left, top, right, bottom) to zero
* before returning.
* <p>
* <p>
* If you need to access Adapter for additional data, you can call
* {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the
* View.
*
* @param outRect Rect to receive the output.
* @param view The child view to decorate
* @param parent RecyclerView this ItemDecoration is decorating
* @param state The current state of RecyclerView.
*/
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if ( parent.getChildAdapterPosition(view)==1&&parent.getAdapter().getItemViewType(parent.getChildAdapterPosition(view))==2){
//标题 第一行
outRect.top=PxtransformUtil.dip2px(context,32);
}else if( parent.getChildAdapterPosition(view)!=1&&parent.getAdapter().getItemViewType(parent.getChildAdapterPosition(view))==2){
//标题 第二行
outRect.top=PxtransformUtil.dip2px(context,21);
}else if (parent.getAdapter().getItemViewType(parent.getChildAdapterPosition(view))==3){
//内容
outRect.top=PxtransformUtil.dip2px(context,13);
outRect.right = PxtransformUtil.dip2px(context,23);
outRect.bottom= PxtransformUtil.dip2px(context,11);
}
}
private Context context;
public PGRecyclerViewItemDecoration(Context context) {
this.context=context;
}
}
主页+头部+标题+内容布局:
<?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:clipToPadding="false"
android:clipChildren="false"
android:orientation="vertical"
android:focusable="false"
android:background="#75C11B"
tools:context="com.familybox.ui.family.parents_class.ParentsSchoolActivity">
<com.familybox.ui.family.widget.thrid_party.TvRecyclerView
android:id="@+id/rv_main"
android:focusable="false"
android:clipToPadding="false"
android:paddingLeft="60dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</com.familybox.ui.family.widget.thrid_party.TvRecyclerView>
<LinearLayout
android:orientation="vertical"
android:layout_centerHorizontal="true"
android:layout_below="@+id/rv_main"
android:layout_marginTop="160dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="未收到课程相关推荐"
android:textSize="40sp"
android:textColor="#3A6806 "/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24.67dp"
android:layout_gravity="center_horizontal"
android:text="可能是老师尚未制定本月教学内容"
android:textSize="32sp"
android:textColor="#3A6806 "/>
</LinearLayout>
</RelativeLayout>
<!--
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="42px"
android:layout_marginTop="48px"
android:focusable="true"
android:background="#f00"
android:gravity="center">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_main"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</FrameLayout>-->
<?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="213.33dp"
android:clipChildren="false"
android:clipToPadding="false"
android:layout_marginLeft="-60dp"
android:layout_marginRight="-60dp"
android:paddingLeft="60dp"
android:focusable="true"
android:id="@+id/rl_tool"
android:background="@mipmap/gexing_top"
tools:context="com.familybox.ui.family.parents_class.ParentsSchoolActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="个性成长"
android:textStyle="bold"
android:focusable="false"
android:id="@+id/tv_tag"
android:layout_marginTop="40dp"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="@dimen/font_size_48"/>
<LinearLayout
android:orientation="horizontal"
android:layout_marginTop="101.33dp"
android:gravity="center"
android:focusable="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:layout_marginTop="3dp"
android:textColor="#CDE7B0"
android:gravity="center"
android:text="@string/gexingchengzhang_tag_01"/>
<ImageView
android:layout_width="33.33dp"
android:layout_height="33.33dp"
android:scaleType="fitCenter"
android:src="@mipmap/gxcz_ico"
android:layout_gravity="center_vertical"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="24sp"
android:gravity="center"
android:layout_marginTop="3dp"
android:textColor="#CDE7B0"
android:text="@string/gexingchengzhang_tag_02"/>
</LinearLayout>
<LinearLayout
android:id="@+id/ll_tool"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="144dp"
android:focusable="true"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_01"
android:layout_width="213.33dp"
android:layout_height="66.67dp"
android:text="课程相关"
android:nextFocusRight="@+id/tv_02"
android:focusable="true"
android:background="@drawable/sel_focus_gp2"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="@dimen/font_size_24"/>
<TextView
android:id="@+id/tv_02"
android:focusable="true"
android:layout_width="213.33dp"
android:layout_height="66.67dp"
android:text="测评推荐"
android:nextFocusRight="@+id/tv_03"
android:background="@drawable/sel_focus_gp2"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="@dimen/font_size_24"/>
<TextView
android:focusable="true"
android:id="@+id/tv_03"
android:layout_width="213.33dp"
android:layout_height="66.67dp"
android:text="家长订阅"
android:background="@drawable/sel_focus_gp2"
android:gravity="center"
android:textColor="#ffffff"
android:textSize="@dimen/font_size_24"/>
</LinearLayout>
</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="wrap_content"
android:clipToPadding="false"
android:background="#75C11B"
android:layout_marginLeft="-60dp"
android:layout_marginRight="-60dp"
android:paddingLeft="60dp"
android:clipChildren="false"
android:orientation="vertical"
android:focusable="false"
tools:context="com.familybox.ui.family.parents_class.ParentsSchoolActivity">
<TextView
android:id="@+id/tv_title"
android:layout_marginTop="32dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textStyle="bold"
android:textSize="26.67sp"
android:clickable="false"
android:focusableInTouchMode="false"
android:focusable="false"
android:textColor="@android:color/white"
/>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_gravity="center"
android:id="@+id/fl_content"
android:clipChildren="false"
android:clipToPadding="false"
android:focusable="true"
android:gravity="center">
<RelativeLayout
android:id="@+id/rl_select"
android:layout_centerHorizontal="true"
android:layout_width="150dp"
android:layout_height="120dp">
<android.support.v7.widget.CardView
android:id="@+id/cv_01"
app:cardPreventCornerOverlap="false"
android:padding="3dp"
android:clipChildren="false"
android:layout_width="142dp"
android:layout_height="90dp"
app:cardCornerRadius="3dp">
<RelativeLayout
android:id="@+id/rl_img"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#333"
android:clipChildren="false"></RelativeLayout>
</android.support.v7.widget.CardView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/cv_01"
android:layout_marginTop="5.33dp"
android:layout_centerHorizontal="true"
android:textSize="18.67sp"
android:gravity="center_vertical"
android:textColor="#ffffff"
android:id="@+id/tv_content"
android:text="dddddddddddd"/>
<!-- <TextView
android:layout_width="120.33dp"
android:layout_height="22.67dp"
android:background="#ffffff"
android:layout_marginTop="80.6dp"
android:layout_centerHorizontal="true"
android:textSize="18.67sp"
android:textColor="#000000"
android:visibility="gone"
android:id="@+id/tv_content_s"
android:text="dd"/>-->
</RelativeLayout>
<!-- <RelativeLayout
android:id="@+id/rl_select"
android:layout_width="150dp"
android:layout_height="120dp"
android:clipChildren="false"
android:visibility="gone">
<RelativeLayout
android:padding="3dp"
android:id="@+id/rl_img2"
android:background="@drawable/border_color"
android:layout_width="150dp"
android:layout_height="100dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#333"/>
</RelativeLayout>
</RelativeLayout>-->
<TextView
android:layout_width="120.33dp"
android:layout_height="22.67dp"
android:background="#ffffff"
android:visibility="gone"
android:layout_marginTop="78.6dp"
android:layout_centerHorizontal="true"
android:textSize="18.67sp"
android:textColor="#000000"
android:id="@+id/tv_content_s"
android:text="dd"/>
</RelativeLayout>
模拟的数据:
package com.familybox.ui.demo;
import java.util.List;
/**
* Created by coderShan on 2018/4/13.
*/
public class TestData01 {
private int type;//判断是标题0还是内容1还是头部3
private boolean isSelect;//判断当前是否被选中
private String text;//显示的文本
private String pic;//图片的连接
private boolean func;//用于标记取消订阅按钮
private String connect_title;//如果是内容,存放内容的标题
private String delete_title;//如果是取消订阅的按钮,存放的要取消订阅的标题
public TestData01(int type, boolean isSelect, String text, String pic, boolean func, String connect_title, String delete_title) {
this.type = type;
this.isSelect = isSelect;
this.text = text;
this.pic = pic;
this.func = func;
this.connect_title = connect_title;
this.delete_title = delete_title;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public boolean isSelect() {
return isSelect;
}
public void setSelect(boolean select) {
isSelect = select;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic;
}
public boolean isFunc() {
return func;
}
public void setFunc(boolean func) {
this.func = func;
}
public String getConnect_title() {
return connect_title;
}
public void setConnect_title(String connect_title) {
this.connect_title = connect_title;
}
public String getDelete_title() {
return delete_title;
}
public void setDelete_title(String delete_title) {
this.delete_title = delete_title;
}
}
总结
电视开发的难点其实不多,只要心中有焦点在哪个位置的逼数,大概就能驰骋绝大部分tv项目了,因为tv的UI其实很固定。
其实android的难点也不多,除了贼复杂的自定义view(算法)以及不用自己去编译什么so库(其他语言),android应该没什
么难点存在了。面试也有好多问react native混合开发的,我除了对热修复一知半解外也是一脸懵逼,这也是我今年的研究方向。