├── .gitignore ├── README.md ├── build.gradle ├── example ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── owen │ │ └── tvrecyclerview │ │ └── example │ │ ├── LayoutAdapter.java │ │ ├── LayoutFragment.java │ │ └── MainActivity.java │ └── res │ ├── drawable-hdpi │ ├── ic_grid.png │ ├── ic_launcher.png │ ├── ic_list.png │ ├── ic_spannable.png │ ├── ic_spannable_selected.png │ └── ic_staggered.png │ ├── drawable │ ├── divider.xml │ ├── item_background.xml │ └── selector_ic_spannable.xml │ ├── layout │ ├── activity_main.xml │ ├── item.xml │ ├── layout_grid.xml │ ├── layout_list.xml │ ├── layout_spannable_grid.xml │ └── layout_staggered_grid.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── images ├── img_grid.png ├── img_list.png ├── img_spannable.png └── img_staggered.png ├── library ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── owen │ │ └── tvrecyclerview │ │ ├── BaseLayoutManager.java │ │ ├── ItemEntries.java │ │ ├── Lanes.java │ │ ├── TwoWayLayoutManager.java │ │ └── widget │ │ ├── DividerItemDecoration.java │ │ ├── GridLayoutManager.java │ │ ├── ItemSpacingOffsets.java │ │ ├── ListLayoutManager.java │ │ ├── SpacingItemDecoration.java │ │ ├── SpannableGridLayoutManager.java │ │ ├── StaggeredGridLayoutManager.java │ │ └── TvRecyclerView.java │ └── res │ └── values │ ├── attrs.xml │ └── strings.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 欢迎使用 TvRecyclerView 2 | 3 | 首先感谢lucasr开发出杰出的作品[TwoWayView](https://github.com/lucasr/twoway-view),**TvRecyclerView**就是在[TwoWayView](https://github.com/lucasr/twoway-view)的基础上进行的延伸,即: 4 | 5 | > * 修复了一些小bug 6 | > * 针对TV端的特性进行了适配与开发 7 | 8 | ### 效果 9 | 10 | ![](https://github.com/zhousuqiang/TvRecyclerView/blob/master/images/img_spannable.png) 11 | 12 | ![](https://github.com/zhousuqiang/TvRecyclerView/blob/master/images/img_staggered.png) 13 | 14 | ![](https://github.com/zhousuqiang/TvRecyclerView/blob/master/images/img_grid.png) 15 | 16 | ![](https://github.com/zhousuqiang/TvRecyclerView/blob/master/images/img_list.png) 17 | 18 | ### Android Studio 集成 19 | 20 | ```java 21 | compile 'com.tv.boost:tv-recyclerview:1.0.1' 22 | ``` 23 | 24 | ### 特性 25 | 26 | - [x] 支持焦点快速移动 27 | 28 | - [x] 支持Item选中放大时不被叠压(无需手动调用bringChildToFront()) 29 | 30 | - [x] 支持横/竖排列 31 | ```java 32 | android:orientation="horizontal" 33 | ``` 34 | 35 | - [x] 支持布局指定LayoutManager 36 | ```java 37 | app:tv_layoutManager="SpannableGridLayoutManager" 38 | ``` 39 | 40 | - [x] 支持设置选中Item边缘距离/居中 41 | ```java 42 | setSelectedItemAtCentered(boolean isCentered) 43 | setSelectedItemOffset(int offsetStart, int offsetEnd) 44 | ``` 45 | 46 | - [x] 支持设置横竖间距 47 | ```java 48 | setSpacingWithMargins(int verticalSpacing, int horizontalSpacing) 49 | ``` 50 | 51 | - [x] Item监听回调 52 | ```java 53 | mRecyclerView.setOnItemListener(new TvRecyclerView.OnItemListener() { 54 | @Override 55 | public void onItemPreSelected(TvRecyclerView parent, View itemView, int position) { 56 | 57 | } 58 | 59 | @Override 60 | public void onItemSelected(TvRecyclerView parent, View itemView, int position) { 61 | 62 | } 63 | 64 | @Override 65 | public void onItemClick(TvRecyclerView parent, View itemView, int position) { 66 | 67 | } 68 | }); 69 | ``` 70 | 71 | 72 | ### 更详细的使用请见exmaple 73 | 74 | ------ 75 | 76 | 77 | 作者 [owen](https://github.com/zhousuqiang) 78 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.1.2' 9 | 10 | classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' //自动化maven打包插件 11 | classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.6' //自动上传至Bintray平台插件 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /example/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.3" 6 | 7 | defaultConfig { 8 | applicationId "com.owen.tvrecyclerview.example" 9 | minSdkVersion 14 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.4.0' 26 | compile project(':library') 27 | } 28 | -------------------------------------------------------------------------------- /example/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/owen/Documents/Developer_Tool/adt-bundle-mac-x86_64-20131030/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /example/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /example/src/main/java/com/owen/tvrecyclerview/example/LayoutAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Lucas Rocha 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.owen.tvrecyclerview.example; 18 | 19 | import android.content.Context; 20 | import android.support.v7.widget.RecyclerView; 21 | import android.view.LayoutInflater; 22 | import android.view.View; 23 | import android.view.ViewGroup; 24 | import android.widget.TextView; 25 | 26 | import com.owen.tvrecyclerview.TwoWayLayoutManager; 27 | import com.owen.tvrecyclerview.widget.SpannableGridLayoutManager; 28 | import com.owen.tvrecyclerview.widget.StaggeredGridLayoutManager; 29 | import com.owen.tvrecyclerview.widget.TvRecyclerView; 30 | 31 | import java.util.ArrayList; 32 | import java.util.List; 33 | 34 | public class LayoutAdapter extends RecyclerView.Adapter { 35 | private static final int COUNT = 50; 36 | 37 | private final Context mContext; 38 | private final TvRecyclerView mRecyclerView; 39 | private final List mItems; 40 | private final int mLayoutId; 41 | private int mCurrentItemId = 0; 42 | 43 | public static class SimpleViewHolder extends RecyclerView.ViewHolder { 44 | public final TextView title; 45 | 46 | public SimpleViewHolder(View view) { 47 | super(view); 48 | title = (TextView) view.findViewById(R.id.title); 49 | } 50 | } 51 | 52 | public LayoutAdapter(Context context, TvRecyclerView recyclerView, int layoutId) { 53 | mContext = context; 54 | mItems = new ArrayList(COUNT); 55 | for (int i = 0; i < COUNT; i++) { 56 | addItem(i); 57 | } 58 | 59 | mRecyclerView = recyclerView; 60 | mLayoutId = layoutId; 61 | } 62 | 63 | public void addItem(int position) { 64 | final int id = mCurrentItemId++; 65 | mItems.add(position, id); 66 | notifyItemInserted(position); 67 | } 68 | 69 | public void removeItem(int position) { 70 | mItems.remove(position); 71 | notifyItemRemoved(position); 72 | } 73 | 74 | @Override 75 | public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 76 | final View view = LayoutInflater.from(mContext).inflate(R.layout.item, parent, false); 77 | return new SimpleViewHolder(view); 78 | } 79 | 80 | @Override 81 | public void onBindViewHolder(SimpleViewHolder holder, final int position) { 82 | holder.title.setText(mItems.get(position).toString()); 83 | 84 | boolean isVertical = (mRecyclerView.getOrientation() == TwoWayLayoutManager.Orientation.VERTICAL); 85 | final View itemView = holder.itemView; 86 | final int itemId = mItems.get(position); 87 | 88 | if (mLayoutId == R.layout.layout_staggered_grid) { 89 | final int dimenId; 90 | if (itemId % 3 == 0) { 91 | dimenId = R.dimen.staggered_child_medium; 92 | } else if (itemId % 5 == 0) { 93 | dimenId = R.dimen.staggered_child_large; 94 | } else if (itemId % 7 == 0) { 95 | dimenId = R.dimen.staggered_child_xlarge; 96 | } else { 97 | dimenId = R.dimen.staggered_child_small; 98 | } 99 | 100 | final int span; 101 | if (itemId == 2) { 102 | span = 2; 103 | } else { 104 | span = 1; 105 | } 106 | 107 | final int size = mContext.getResources().getDimensionPixelSize(dimenId); 108 | 109 | final StaggeredGridLayoutManager.LayoutParams lp = 110 | (StaggeredGridLayoutManager.LayoutParams) itemView.getLayoutParams(); 111 | 112 | if (!isVertical) { 113 | lp.span = span; 114 | lp.width = size; 115 | itemView.setLayoutParams(lp); 116 | } else { 117 | lp.span = span; 118 | lp.height = size; 119 | itemView.setLayoutParams(lp); 120 | } 121 | } else if (mLayoutId == R.layout.layout_spannable_grid) { 122 | final SpannableGridLayoutManager.LayoutParams lp = 123 | (SpannableGridLayoutManager.LayoutParams) itemView.getLayoutParams(); 124 | 125 | final int span1 = (itemId == 0 || itemId == 6 || itemId == 13 || itemId == 5 ? 2 : 1); 126 | final int span2 = (itemId == 0 || itemId == 6 || itemId == 13 ? 2 : itemId == 5 ? 4 : 1); 127 | 128 | final int colSpan = (isVertical ? span2 : span1); 129 | final int rowSpan = (isVertical ? span1 : span2); 130 | if (lp.rowSpan != rowSpan || lp.colSpan != colSpan) { 131 | lp.rowSpan = rowSpan; 132 | lp.colSpan = colSpan; 133 | 134 | itemView.setLayoutParams(lp); 135 | } 136 | } 137 | } 138 | 139 | @Override 140 | public int getItemCount() { 141 | return mItems.size(); 142 | } 143 | 144 | public interface OnItemSelectedListenner { 145 | void onSelected(View view, int positin); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /example/src/main/java/com/owen/tvrecyclerview/example/LayoutFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Lucas Rocha 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.owen.tvrecyclerview.example; 18 | 19 | import android.app.Activity; 20 | import android.os.Bundle; 21 | import android.support.v4.app.Fragment; 22 | import android.support.v7.widget.RecyclerView; 23 | import android.view.Gravity; 24 | import android.view.LayoutInflater; 25 | import android.view.View; 26 | import android.view.ViewGroup; 27 | import android.widget.TextView; 28 | import android.widget.Toast; 29 | 30 | import com.owen.tvrecyclerview.widget.TvRecyclerView; 31 | 32 | import static android.support.v7.widget.RecyclerView.SCROLL_STATE_DRAGGING; 33 | import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE; 34 | import static android.support.v7.widget.RecyclerView.SCROLL_STATE_SETTLING; 35 | 36 | public class LayoutFragment extends Fragment { 37 | private static final String ARG_LAYOUT_ID = "layout_id"; 38 | 39 | private TvRecyclerView mRecyclerView; 40 | private TextView mPositionText; 41 | private TextView mCountText; 42 | private TextView mStateText; 43 | private Toast mToast; 44 | 45 | private int mLayoutId; 46 | 47 | public static LayoutFragment newInstance(int layoutId) { 48 | LayoutFragment fragment = new LayoutFragment(); 49 | 50 | Bundle args = new Bundle(); 51 | args.putInt(ARG_LAYOUT_ID, layoutId); 52 | fragment.setArguments(args); 53 | 54 | return fragment; 55 | } 56 | 57 | @Override 58 | public void onCreate(Bundle savedInstanceState) { 59 | super.onCreate(savedInstanceState); 60 | mLayoutId = getArguments().getInt(ARG_LAYOUT_ID); 61 | } 62 | 63 | @Override 64 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 65 | Bundle savedInstanceState) { 66 | return inflater.inflate(mLayoutId, container, false); 67 | } 68 | 69 | @Override 70 | public void onViewCreated(View view, Bundle savedInstanceState) { 71 | super.onViewCreated(view, savedInstanceState); 72 | 73 | final Activity activity = getActivity(); 74 | 75 | mToast = Toast.makeText(activity, "", Toast.LENGTH_SHORT); 76 | mToast.setGravity(Gravity.CENTER, 0, 0); 77 | 78 | View btnView = view.findViewById(R.id.btn1); 79 | if(null != btnView) { 80 | btnView.setOnClickListener(new View.OnClickListener() { 81 | @Override 82 | public void onClick(View v) { 83 | mRecyclerView.smoothScrollToPosition(15); 84 | } 85 | }); 86 | } 87 | 88 | mRecyclerView = (TvRecyclerView) view.findViewById(R.id.list); 89 | mRecyclerView.setHasFixedSize(true); 90 | mRecyclerView.setLongClickable(true); 91 | 92 | mPositionText = (TextView) view.getRootView().findViewById(R.id.position); 93 | mCountText = (TextView) view.getRootView().findViewById(R.id.count); 94 | 95 | mStateText = (TextView) view.getRootView().findViewById(R.id.state); 96 | updateState(SCROLL_STATE_IDLE); 97 | 98 | mRecyclerView.setOnItemListener(new TvRecyclerView.OnItemListener() { 99 | @Override 100 | public void onItemPreSelected(TvRecyclerView parent, View itemView, int position) { 101 | itemView.animate().scaleX(1f).scaleY(1f).setDuration(300).start(); 102 | } 103 | 104 | @Override 105 | public void onItemSelected(TvRecyclerView parent, View itemView, int position) { 106 | itemView.animate().scaleX(1.4f).scaleY(1.4f).setDuration(300).start(); 107 | } 108 | 109 | @Override 110 | public void onItemClick(TvRecyclerView parent, View itemView, int position) { 111 | mToast.setText("onItemClick::"+position); 112 | mToast.show(); 113 | } 114 | }); 115 | 116 | mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 117 | @Override 118 | public void onScrollStateChanged(RecyclerView recyclerView, int scrollState) { 119 | updateState(scrollState); 120 | } 121 | 122 | @Override 123 | public void onScrolled(RecyclerView recyclerView, int i, int i2) { 124 | mPositionText.setText("First: " + mRecyclerView.getFirstVisiblePosition()); 125 | mCountText.setText("Count: " + mRecyclerView.getChildCount()); 126 | } 127 | }); 128 | 129 | 130 | // final Drawable divider = getResources().getDrawable(R.drawable.divider); 131 | // mRecyclerView.addItemDecoration(new DividerItemDecoration(divider)); 132 | // mRecyclerView.addItemDecoration(new SpacingItemDecoration(20, 20)); 133 | // 通过Margins来设置布局的横纵间距(与addItemDecoration()方法可二选一) 134 | // 推荐使用此方法 135 | mRecyclerView.setSpacingWithMargins(18, 18); 136 | 137 | 138 | // 设置选中的Item距离开始或结束的偏移量(与setSelectedItemAtCentered()方法二选一) 139 | // mRecyclerView.setSelectedItemOffset(120, 120); 140 | // 设置选中的Item居中(与setSelectedItemOffset()方法二选一) 141 | mRecyclerView.setSelectedItemAtCentered(true); 142 | 143 | mRecyclerView.setAdapter(new LayoutAdapter(activity, mRecyclerView, mLayoutId)); 144 | } 145 | 146 | private void updateState(int scrollState) { 147 | String stateName = "Undefined"; 148 | switch(scrollState) { 149 | case SCROLL_STATE_IDLE: 150 | stateName = "Idle"; 151 | break; 152 | 153 | case SCROLL_STATE_DRAGGING: 154 | stateName = "Dragging"; 155 | break; 156 | 157 | case SCROLL_STATE_SETTLING: 158 | stateName = "Flinging"; 159 | break; 160 | } 161 | 162 | mStateText.setText(stateName); 163 | } 164 | 165 | public int getLayoutId() { 166 | return getArguments().getInt(ARG_LAYOUT_ID); 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /example/src/main/java/com/owen/tvrecyclerview/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Lucas Rocha 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.owen.tvrecyclerview.example; 18 | 19 | import android.os.Bundle; 20 | import android.support.v4.app.FragmentTransaction; 21 | import android.support.v7.app.ActionBar; 22 | import android.support.v7.app.AppCompatActivity; 23 | import android.util.Log; 24 | import android.view.KeyEvent; 25 | 26 | public class MainActivity extends AppCompatActivity { 27 | private final String LOGTAG = MainActivity.class.getSimpleName(); 28 | private final String ARG_SELECTED_LAYOUT_ID = "selectedLayoutId"; 29 | 30 | private final int DEFAULT_LAYOUT = R.layout.layout_list; 31 | 32 | private int mSelectedLayoutId; 33 | 34 | @Override 35 | protected void onCreate(Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | setContentView(R.layout.activity_main); 38 | 39 | ActionBar actionBar = getSupportActionBar(); 40 | actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 41 | actionBar.setDisplayShowTitleEnabled(false); 42 | actionBar.setDisplayShowHomeEnabled(false); 43 | 44 | mSelectedLayoutId = DEFAULT_LAYOUT; 45 | if (savedInstanceState != null) { 46 | mSelectedLayoutId = savedInstanceState.getInt(ARG_SELECTED_LAYOUT_ID); 47 | } 48 | 49 | addLayoutTab( 50 | actionBar, R.layout.layout_list, R.drawable.ic_list, "list"); 51 | addLayoutTab( 52 | actionBar, R.layout.layout_grid, R.drawable.ic_grid, "grid"); 53 | addLayoutTab( 54 | actionBar, R.layout.layout_staggered_grid, R.drawable.ic_staggered, "staggered"); 55 | addLayoutTab( 56 | actionBar, R.layout.layout_spannable_grid, R.drawable.selector_ic_spannable, "spannable"); 57 | } 58 | 59 | @Override 60 | protected void onSaveInstanceState(Bundle outState) { 61 | super.onSaveInstanceState(outState); 62 | outState.putInt(ARG_SELECTED_LAYOUT_ID, mSelectedLayoutId); 63 | } 64 | 65 | private void addLayoutTab(ActionBar actionBar, int layoutId, int iconId, String tag) { 66 | ActionBar.Tab tab = actionBar.newTab() 67 | // .setText(tag) 68 | .setIcon(iconId) 69 | .setTabListener(new TabListener(layoutId, tag)); 70 | actionBar.addTab(tab, layoutId == mSelectedLayoutId); 71 | } 72 | 73 | @Override 74 | public boolean dispatchKeyEvent(KeyEvent event) { 75 | return super.dispatchKeyEvent(event); 76 | } 77 | 78 | @Override 79 | public boolean onKeyDown(int keyCode, KeyEvent event) { 80 | Log.d(LOGTAG, "keyCode="+keyCode); 81 | return super.onKeyDown(keyCode, event); 82 | } 83 | 84 | public class TabListener implements ActionBar.TabListener { 85 | private LayoutFragment mFragment; 86 | private final int mLayoutId; 87 | private final String mTag; 88 | 89 | public TabListener(int layoutId, String tag) { 90 | mLayoutId = layoutId; 91 | mTag = tag; 92 | } 93 | 94 | @Override 95 | public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) { 96 | mFragment = (LayoutFragment) getSupportFragmentManager().findFragmentByTag(mTag); 97 | if (mFragment == null) { 98 | mFragment = (LayoutFragment) LayoutFragment.newInstance(mLayoutId); 99 | ft.add(R.id.content, mFragment, mTag); 100 | } else { 101 | ft.attach(mFragment); 102 | } 103 | 104 | mSelectedLayoutId = mFragment.getLayoutId(); 105 | } 106 | 107 | @Override 108 | public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) { 109 | if (mFragment != null) { 110 | ft.detach(mFragment); 111 | } 112 | } 113 | 114 | @Override 115 | public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) { 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /example/src/main/res/drawable-hdpi/ic_grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrozenFreeFall/TvRecyclerView/4a4e3bf9a43ed01f07d6e8098f562d55e3b32f22/example/src/main/res/drawable-hdpi/ic_grid.png -------------------------------------------------------------------------------- /example/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrozenFreeFall/TvRecyclerView/4a4e3bf9a43ed01f07d6e8098f562d55e3b32f22/example/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/src/main/res/drawable-hdpi/ic_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrozenFreeFall/TvRecyclerView/4a4e3bf9a43ed01f07d6e8098f562d55e3b32f22/example/src/main/res/drawable-hdpi/ic_list.png -------------------------------------------------------------------------------- /example/src/main/res/drawable-hdpi/ic_spannable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrozenFreeFall/TvRecyclerView/4a4e3bf9a43ed01f07d6e8098f562d55e3b32f22/example/src/main/res/drawable-hdpi/ic_spannable.png -------------------------------------------------------------------------------- /example/src/main/res/drawable-hdpi/ic_spannable_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrozenFreeFall/TvRecyclerView/4a4e3bf9a43ed01f07d6e8098f562d55e3b32f22/example/src/main/res/drawable-hdpi/ic_spannable_selected.png -------------------------------------------------------------------------------- /example/src/main/res/drawable-hdpi/ic_staggered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrozenFreeFall/TvRecyclerView/4a4e3bf9a43ed01f07d6e8098f562d55e3b32f22/example/src/main/res/drawable-hdpi/ic_staggered.png -------------------------------------------------------------------------------- /example/src/main/res/drawable/divider.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 19 | 20 | 21 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /example/src/main/res/drawable/item_background.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 21 | 22 | 24 | 25 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /example/src/main/res/drawable/selector_ic_spannable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 21 | 22 | 26 | 27 | 31 | 32 | 35 | 36 | 39 | 40 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/src/main/res/layout/item.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | -------------------------------------------------------------------------------- /example/src/main/res/layout/layout_grid.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 28 | -------------------------------------------------------------------------------- /example/src/main/res/layout/layout_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 23 | 24 |