getMenuDatas() {
152 | return mItems;
153 | }
154 |
155 | }
156 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/menu/OpenMenuItem.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.menu;
2 |
3 | /**
4 | * 菜单item接口.
5 | *
6 | * @author hailongqiu
7 | */
8 | public interface OpenMenuItem {
9 | static final int NO_ICON = 0; // 默认icon id.
10 | static final int DEFAULT_TEXT_SIZE = 24; // 默认字体
11 |
12 | /**
13 | * 设置菜单item-ID.
14 | */
15 | public OpenMenuItem setId(int id);
16 |
17 | public int getId();
18 |
19 | /**
20 | * 设置菜单资源.
21 | */
22 | public OpenMenuItem setIconRes(int iconID);
23 | public int getIconRes();
24 |
25 | /**
26 | * 设置菜单文本内容
27 | */
28 | public OpenMenuItem setTitle(CharSequence title);
29 |
30 | public CharSequence getTitle();
31 |
32 | /**
33 | * 设置字体大小.
34 | */
35 | public OpenMenuItem setTextSize(int size);
36 |
37 | public int getTextSize();
38 |
39 | /**
40 | * 设置数据.
41 | */
42 | public OpenMenuItem setObjectData(Object data);
43 |
44 | public Object getObjectData();
45 |
46 | /**
47 | * 添加子菜单.
48 | */
49 | public OpenMenuItem addSubMenu(OpenMenu openSubMenu);
50 |
51 | public OpenMenu getSubMenu();
52 |
53 | public OpenMenuItem showSubMenu();
54 | public OpenMenuItem hideSubMenu();
55 |
56 | /**
57 | * 判断子菜单是否存在.
58 | */
59 | public boolean hasSubMenu();
60 |
61 | /**
62 | * 判断子菜单是否显示了.
63 | */
64 | public boolean isShowSubMenu();
65 | public void setShowSubMenu(boolean isShow);
66 |
67 | /**
68 | * 设置checked标志位.
69 | */
70 | public OpenMenuItem setChecked(boolean checked);
71 |
72 | public boolean isChecked();
73 |
74 | public OpenMenu getMenu();
75 | public void setMenu(OpenMenu menu);
76 |
77 | /**
78 | * 菜单item接口函数.
79 | */
80 | public interface ItemView {
81 | public void initialize(OpenMenuItem itemData);
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/menu/OpenMenuItemImpl.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.menu;
2 |
3 | public class OpenMenuItemImpl implements OpenMenuItem {
4 |
5 | private int mIconID; // icon 资源 id.
6 | private int mId; // item id.
7 | private int mTextSize = DEFAULT_TEXT_SIZE; // item 文本大小.
8 | private boolean mChecked = false; // item 勾选状态.
9 | private boolean mIsShowSubMenu = false; // 是否显示子菜单.
10 | private Object mData;
11 | private CharSequence mTitle; // item 文本.
12 |
13 | private OpenMenu mMenu; // 保存 item的父菜单.
14 | private OpenMenu mSubMenu; // 保存 子菜单.
15 |
16 |
17 | OpenMenuItemImpl(OpenMenu menu, int id, CharSequence title) {
18 | this.mMenu = menu;
19 | this.mId = id;
20 | this.mTitle = title;
21 | }
22 |
23 | @Override
24 | public OpenMenuItem showSubMenu() {
25 | if (mSubMenu != null) {
26 | mSubMenu.showMenu();
27 | }
28 | this.mIsShowSubMenu = true;
29 | return this;
30 | }
31 |
32 | @Override
33 | public OpenMenuItem hideSubMenu() {
34 | if (mSubMenu != null) {
35 | mSubMenu.hideMenu();
36 | }
37 | this.mIsShowSubMenu = false;
38 | return this;
39 | }
40 |
41 | /**
42 | * 设置 图标资源id.
43 | */
44 | @Override
45 | public OpenMenuItem setIconRes(int iconID) {
46 | this.mIconID = iconID;
47 | notifyChanged();
48 | return this;
49 | }
50 |
51 | @Override
52 | public int getIconRes() {
53 | return this.mIconID;
54 | }
55 |
56 | @Override
57 | public OpenMenuItem setTitle(CharSequence title) {
58 | this.mTitle = title;
59 | notifyChanged();
60 | return this;
61 | }
62 |
63 | @Override
64 | public CharSequence getTitle() {
65 | return mTitle;
66 | }
67 |
68 | /**
69 | * 添加子菜单.
70 | */
71 | @Override
72 | public OpenMenuItem addSubMenu(OpenMenu openSubMenu) {
73 | this.mSubMenu = openSubMenu;
74 | this.mSubMenu.setParentMenu(mMenu); // 添加父菜单.
75 | return this;
76 | }
77 |
78 | @Override
79 | public OpenMenu getSubMenu() {
80 | return mSubMenu;
81 | }
82 |
83 | @Override
84 | public boolean hasSubMenu() {
85 | return (mSubMenu != null);
86 | }
87 |
88 | @Override
89 | public boolean isShowSubMenu() {
90 | return this.mIsShowSubMenu;
91 | }
92 |
93 | @Override
94 | public void setShowSubMenu(boolean isShow) {
95 | this.mIsShowSubMenu = isShow;
96 | }
97 |
98 | @Override
99 | public OpenMenuItem setChecked(boolean checked) {
100 | this.mChecked = checked;
101 | notifyChanged();
102 | return this;
103 | }
104 |
105 | @Override
106 | public boolean isChecked() {
107 | return this.mChecked;
108 | }
109 |
110 | @Override
111 | public OpenMenuItem setTextSize(int size) {
112 | mTextSize = size;
113 | notifyChanged();
114 | return this;
115 | }
116 |
117 | @Override
118 | public int getTextSize() {
119 | return mTextSize;
120 | }
121 |
122 | @Override
123 | public OpenMenuItem setObjectData(Object data) {
124 | this.mData = data;
125 | notifyChanged();
126 | return this;
127 | }
128 |
129 | @Override
130 | public Object getObjectData() {
131 | return this.mData;
132 | }
133 |
134 | @Override
135 | public OpenMenuItem setId(int id) {
136 | this.mId = id;
137 | return this;
138 | }
139 |
140 | @Override
141 | public int getId() {
142 | return this.mId;
143 | }
144 |
145 | /**
146 | * 数据更新.
147 | */
148 |
149 | private void notifyChanged() {
150 | if (mMenu != null) {
151 | mMenu.notifyChanged();
152 | }
153 | }
154 |
155 | public OpenMenu getMenu() {
156 | return this.mMenu;
157 | }
158 |
159 | @Override
160 | public void setMenu(OpenMenu menu) {
161 | this.mMenu = menu;
162 | }
163 |
164 | }
165 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/menu/OpenMenuItemView.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.menu;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.util.AttributeSet;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.CompoundButton;
10 | import android.widget.ImageView;
11 | import android.widget.LinearLayout;
12 | import android.widget.RadioButton;
13 | import android.widget.TextView;
14 |
15 | import com.open.androidtvwidget.R;
16 | import com.open.androidtvwidget.utils.GenerateViewId;
17 | import com.open.androidtvwidget.utils.OPENLOG;
18 |
19 | /**
20 | * Created by hailongqiu on 2016/8/23.
21 | */
22 | public class OpenMenuItemView extends LinearLayout implements OpenMenuItem.ItemView {
23 | private OpenMenuItem mItemData;
24 | private Context mContext;
25 |
26 | private ImageView mIconView;
27 | private CompoundButton mCompoundButton;
28 | private TextView mTitleView;
29 |
30 | private LayoutInflater mInflater;
31 |
32 | public OpenMenuItemView(Context context) {
33 | this(context, null, 0);
34 | }
35 |
36 | public OpenMenuItemView(Context context, AttributeSet attrs) {
37 | this(context, attrs, 0);
38 | }
39 |
40 | public OpenMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) {
41 | super(context, attrs, defStyleAttr);
42 | this.mContext = context;
43 | //
44 | setFocusableInTouchMode(true);
45 | setFocusable(true);
46 | }
47 |
48 | @Override
49 | protected void onFinishInflate() {
50 | super.onFinishInflate();
51 | mTitleView = (TextView) findViewById(R.id.title_tv);
52 | }
53 |
54 | @Override
55 | public void initialize(OpenMenuItem itemData) {
56 | this.mItemData = itemData;
57 | //
58 | setTitle(itemData.getTitle());
59 | setIcon(itemData.getIconRes());
60 | setTextSize(itemData.getTextSize());
61 | setChecked(itemData, itemData.isChecked());
62 | // 如果没有设置菜单ITEM ID,则默认设置ID.
63 | if (itemData.getId() == 0) {
64 | int id = GenerateViewId.getSingleton().generateViewId();
65 | itemData.setId(id);
66 | }
67 | setId(itemData.getId()); // item ID.
68 | }
69 |
70 | public void setTitle(CharSequence title) {
71 | if (title != null) {
72 | mTitleView.setText(title);
73 | if (mTitleView.getVisibility() != VISIBLE)
74 | mTitleView.setVisibility(VISIBLE);
75 | } else {
76 | if (mTitleView.getVisibility() != GONE)
77 | mTitleView.setVisibility(GONE);
78 | }
79 | }
80 |
81 | public void setIcon(int icon) {
82 | if (mIconView == null && icon <= 0)
83 | return;
84 |
85 | if (mIconView == null) {
86 | insertIconView();
87 | }
88 |
89 | if (icon > 0) {
90 | Drawable d = getContext().getResources().getDrawable(icon);
91 | mIconView.setImageDrawable(d);
92 | if (mIconView.getVisibility() != VISIBLE) {
93 | mIconView.setVisibility(VISIBLE);
94 | }
95 | } else {
96 | mIconView.setVisibility(GONE);
97 | }
98 | }
99 |
100 | public void setChecked(OpenMenuItem itemData, boolean checked) {
101 | // if (itemData.getCheckedView() != null) {
102 | // if (mCompoundButton == null) {
103 | // insertCompoundButton(itemData);
104 | // }
105 | // mCompoundButton.setChecked(checked);
106 | // }
107 | }
108 |
109 | /**
110 | * 设置字体.
111 | */
112 | public void setTextSize(int size) {
113 | if (size > 0) {
114 | mTitleView.setTextSize(size);
115 | }
116 | }
117 |
118 | private void insertIconView() {
119 | LayoutInflater inflater = getInflater();
120 | mIconView = (ImageView) inflater.inflate(R.layout.list_menu_item_icon, this, false);
121 | addView(mIconView, 0);
122 | }
123 |
124 | /**
125 | * 插入勾选view.
126 | */
127 | private void insertCompoundButton(OpenMenuItem itemData) {
128 | mCompoundButton = new RadioButton(mContext);
129 | addView(mCompoundButton, 0);
130 | }
131 |
132 | private LayoutInflater getInflater() {
133 | if (mInflater == null) {
134 | mInflater = LayoutInflater.from(getContext());
135 | }
136 | return mInflater;
137 | }
138 |
139 | @Override
140 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
141 | if (mIconView != null) {
142 | ViewGroup.LayoutParams lp = getLayoutParams();
143 | LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
144 | if (lp.height > 0 && iconLp.width <= 0) {
145 | iconLp.width = lp.height;
146 | }
147 | }
148 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
149 | }
150 |
151 | }
152 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/utils/AnimateUtils.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.utils;
2 |
3 | import android.view.animation.Animation;
4 | import android.view.animation.ScaleAnimation;
5 |
6 | /**
7 | * 动画集合.
8 | *
9 | * @author hailongqiu 356752238@qq.com
10 | *
11 | */
12 | public class AnimateUtils {
13 | public static Animation zoomAnimation(float startScale, float endScale, long duration) {
14 | ScaleAnimation anim = new ScaleAnimation(startScale, endScale, startScale, endScale, Animation.RELATIVE_TO_SELF,
15 | 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
16 | anim.setFillAfter(true);
17 | anim.setDuration(duration);
18 | return anim;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/utils/DisplayUtil.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.utils;
2 |
3 | import android.content.Context;
4 |
5 | public class DisplayUtil {
6 | public static int dip2px(Context context, float dipValue) {
7 | final float scale = context.getResources().getDisplayMetrics().density;
8 | return (int) (dipValue * scale + 0.5f);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/utils/DrawUtils.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.utils;
2 |
3 | import android.graphics.Path;
4 | import android.graphics.RectF;
5 |
6 | public class DrawUtils {
7 |
8 | public static Path addRoundPath3(int width, int height, float radius) {
9 | Path path = new Path();
10 | path.addRoundRect(new RectF(0, 0, width, height), radius, radius, Path.Direction.CW);
11 | return path;
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/utils/GenerateViewId.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.utils;
2 |
3 | import java.util.concurrent.atomic.AtomicInteger;
4 |
5 | import android.annotation.SuppressLint;
6 | import android.os.Build;
7 | import android.view.View;
8 |
9 | public class GenerateViewId {
10 | private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
11 | private static GenerateViewId sGenerateViewId = new GenerateViewId();
12 |
13 | public static GenerateViewId getSingleton() {
14 | return sGenerateViewId;
15 | }
16 |
17 | /**
18 | * 动态生成View ID API LEVEL 17 以上View.generateViewId()生成 API LEVEL 17 以下需要手动生成
19 | */
20 | @SuppressLint("NewApi")
21 | public int generateViewId() {
22 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
23 | for (;;) {
24 | final int result = sNextGeneratedId.get();
25 | // aapt-generated IDs have the high byte nonzero; clamp to the
26 | // range under that.
27 | int newValue = result + 1;
28 | if (newValue > 0x00FFFFFF)
29 | newValue = 1; // Roll over to 1, not 0.
30 | if (sNextGeneratedId.compareAndSet(result, newValue)) {
31 | return result;
32 | }
33 | }
34 | } else {
35 | return View.generateViewId();
36 | }
37 |
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/utils/IdentifierUtuils.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.utils;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * 根据资源名字获取ID.
7 | * Created by hailongqiu on 2016/9/4.
8 | */
9 | public class IdentifierUtuils {
10 |
11 | public static float getIdentifierWidthDimen(Context context, String name) {
12 | try {
13 | if (!name.startsWith("w_"))
14 | name = "w_" + name;
15 | int id = getIdentifierDimen(context, name);
16 | return context.getResources().getDimensionPixelSize(id);
17 | } catch (Exception e) {
18 | e.printStackTrace();
19 | }
20 | return 0;
21 | }
22 |
23 | public static float getIdentifierHeightDimen(Context context, String name) {
24 | try {
25 | if (!name.startsWith("h_"))
26 | name = "h_" + name;
27 | int id = getIdentifierDimen(context, name);
28 | return context.getResources().getDimensionPixelSize(id);
29 | } catch (Exception e) {
30 | e.printStackTrace();
31 | }
32 | return 0;
33 | }
34 |
35 | public static int getIdentifierDimen(Context context, String name) {
36 | int resid = context.getResources().getIdentifier(name, "dimen", context.getPackageName());
37 | return resid;
38 | }
39 |
40 | public static int getIdentifierDrawable(Context context, String name) {
41 | int resid = context.getResources().getIdentifier(name, "drawable", context.getPackageName());
42 | return resid;
43 | }
44 |
45 | public static int getIdentifierString(Context context, String name) {
46 | int resid = context.getResources().getIdentifier(name, "string", context.getPackageName());
47 | return resid;
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/utils/NetWorkUtils.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.utils;
2 |
3 | import android.content.Context;
4 | import android.net.ConnectivityManager;
5 | import android.net.NetworkInfo;
6 |
7 | /**
8 | * 一些网络常用的接口.
9 | * 记得要添加权限哈.
10 | *
11 | *
12 | * @author hailongqiu
13 | *
14 | */
15 | public class NetWorkUtils {
16 |
17 | /**
18 | * 网络是否可用
19 | */
20 | public static boolean isNetWorkdetect(Context context) {
21 | ConnectivityManager conn = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
22 | NetworkInfo networkinfo = conn.getActiveNetworkInfo();
23 | if (networkinfo == null || !networkinfo.isAvailable()) {
24 | return false;
25 | }
26 | return true;
27 | }
28 |
29 | /**
30 | * 判断有线网络.
31 | */
32 | public static boolean checkEthernet(Context context) {
33 | ConnectivityManager conn = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
34 | NetworkInfo networkInfo = conn.getNetworkInfo(ConnectivityManager.TYPE_ETHERNET);
35 | return networkInfo.isConnected();
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/utils/OPENLOG.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.utils;
2 |
3 | import android.text.TextUtils;
4 | import android.util.Log;
5 |
6 | /**
7 | * 使用:
8 | * OPENLOG.initTag("hailongqiu", true); // 测试LOG输出.
9 | * 如果不进行初始化,那么将使用命令来开启LOG输出.
10 | * 开启LOG输出:
11 | *
12 | * setprop log.tag.$getTag() DEBUG
13 | *
14 | *
15 | * @author hailongqiu
16 | */
17 | public class OPENLOG {
18 |
19 | private static String sTag = "";
20 | private static boolean sDebug = false;
21 |
22 | /**
23 | * 初始化tag信息.
24 | */
25 | public static void initTag(String tag) {
26 | initTag(tag, false);
27 | }
28 |
29 | /**
30 | * 初始化设置调试位.
31 | */
32 | public static void initTag(boolean debug) {
33 | initTag(sTag, debug);
34 | }
35 |
36 | public static void initTag(String tag, boolean debug) {
37 | sTag = tag;
38 | sDebug = debug;
39 | }
40 |
41 | public static void D(String str, Object... args) {
42 | if (isDebug()) {
43 | Log.d(getTag(), buildLogString(str, args));
44 | }
45 | }
46 |
47 | public static void V(String str, Object... args) {
48 | if (isDebug()) {
49 | Log.v(getTag(), buildLogString(str, args));
50 | }
51 | }
52 |
53 | public static void E(String str, Object... args) {
54 | if (isDebug()) {
55 | Log.d(getTag(), buildLogString(str, args));
56 | }
57 | }
58 |
59 | /**
60 | * 如果sTAG是空则自动从StackTrace中取TAG
61 | */
62 | private static String getTag() {
63 | if (!TextUtils.isEmpty(sTag)) {
64 | return sTag;
65 | }
66 | StackTraceElement caller = new Throwable().fillInStackTrace().getStackTrace()[2];
67 | return caller.getFileName();
68 | }
69 |
70 | private static String buildLogString(String str, Object... args) {
71 | if (args.length > 0) {
72 | str = String.format(str, args);
73 | }
74 | //
75 | StackTraceElement caller = new Throwable().fillInStackTrace().getStackTrace()[2];
76 | StringBuilder stringBuilder = new StringBuilder();
77 | //
78 | // if (TextUtils.isEmpty(sTag)) {
79 | // stringBuilder.append(caller.getMethodName())
80 | // .append("():")
81 | // .append(caller.getLineNumber())
82 | // .append(":")
83 | // .append(str);
84 | // } else {
85 | stringBuilder
86 | .append("(")
87 | .append(caller.getFileName())
88 | .append(":")
89 | .append(caller.getLineNumber())
90 | .append(").")
91 | .append(caller.getMethodName())
92 | .append("():")
93 | .append(str);
94 | // }
95 | return stringBuilder.toString();
96 | }
97 |
98 | private static boolean isDebug() {
99 | return sDebug || Log.isLoggable(getTag(), Log.DEBUG);
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/utils/Utils.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.utils;
2 |
3 | /**
4 | *
5 | * @author hailongqiu 356752238@qq.com
6 | *
7 | */
8 | public class Utils {
9 |
10 | /**
11 | * 获取SDK版本
12 | */
13 | public static int getSDKVersion() {
14 | int version = 0;
15 | try {
16 | version = Integer.valueOf(android.os.Build.VERSION.SDK);
17 | } catch (NumberFormatException e) {
18 | }
19 | return version;
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/view/ExpendGridView.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.view;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.GridView;
6 |
7 | /**
8 | * 扩展Gridview.必需嵌套滚动窗口.
9 | * @author hailongqiu
10 | *
11 | */
12 | public class ExpendGridView extends GridView {
13 | public ExpendGridView(Context context, AttributeSet attrs, int defStyle) {
14 | super(context, attrs, defStyle);
15 | }
16 |
17 | public ExpendGridView(Context context, AttributeSet attrs) {
18 | super(context, attrs);
19 | }
20 |
21 | @Override
22 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
23 | int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
24 | MeasureSpec.AT_MOST);
25 | super.onMeasure(widthMeasureSpec, expandSpec);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/view/FrameMainLayout.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.view;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 | import android.widget.FrameLayout;
7 |
8 | /**
9 | * 如果有控件放大被挡住,可以使用 MainLayout,
10 | *
11 | * 它继承于 FrameLayout.
12 | *
13 | * 使用方式就和FrameLayout是一样的
14 | *
15 | * 如果你其它的控件也被挡住了,但是这里没有,你可以使用WidgetTvViewBring
16 | *
17 | *
18 | * @author hailongqiu
19 | *
20 | */
21 | public class FrameMainLayout extends FrameLayout {
22 |
23 | public FrameMainLayout(Context context) {
24 | super(context);
25 | init(context);
26 | }
27 |
28 | public FrameMainLayout(Context context, AttributeSet attrs) {
29 | super(context, attrs);
30 | init(context);
31 | }
32 |
33 | WidgetTvViewBring mWidgetTvViewBring;
34 |
35 | private void init(Context context) {
36 | this.setChildrenDrawingOrderEnabled(true);
37 | mWidgetTvViewBring = new WidgetTvViewBring(this);
38 | }
39 |
40 | @Override
41 | public void bringChildToFront(View child) {
42 | mWidgetTvViewBring.bringChildToFront(this, child);
43 | }
44 |
45 | @Override
46 | protected int getChildDrawingOrder(int childCount, int i) {
47 | return mWidgetTvViewBring.getChildDrawingOrder(childCount, i);
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/view/GridViewTV.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.view;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.GridView;
6 |
7 | /**
8 | * GridView TV版本.
9 | *
10 | * @author hailongqiu 356752238@qq.com
11 | */
12 | public class GridViewTV extends GridView {
13 |
14 | public GridViewTV(Context context) {
15 | this(context, null);
16 | }
17 |
18 | public GridViewTV(Context context, AttributeSet attrs) {
19 | super(context, attrs);
20 | init(context, attrs);
21 | }
22 |
23 | @Override
24 | public boolean isInTouchMode() {
25 | return !(hasFocus() && !super.isInTouchMode());
26 | }
27 |
28 | private void init(Context context, AttributeSet attrs) {
29 | this.setChildrenDrawingOrderEnabled(true);
30 | }
31 |
32 | @Override
33 | protected int getChildDrawingOrder(int childCount, int i) {
34 | if (this.getSelectedItemPosition() != -1) {
35 | if (i + this.getFirstVisiblePosition() == this.getSelectedItemPosition()) {// 这是原本要在最后一个刷新的item
36 | return childCount - 1;
37 | }
38 | if (i == childCount - 1) {// 这是最后一个需要刷新的item
39 | return this.getSelectedItemPosition() - this.getFirstVisiblePosition();
40 | }
41 | }
42 | return i;
43 | }
44 |
45 | public void setDefualtSelect(int pos) {
46 | requestFocusFromTouch();
47 | setSelection(pos);
48 | }
49 |
50 | }
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/view/LinearMainLayout.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.view;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 | import android.widget.LinearLayout;
7 |
8 | /**
9 | * 如果有控件放大被挡住,可以使用 LinearMainLayout,
10 | * 它继承于 LinearLayout.
11 | * 使用方式和LinerLayout是一样的
12 | * @author hailongqiu
13 | *
14 | */
15 | public class LinearMainLayout extends LinearLayout {
16 |
17 | public LinearMainLayout(Context context) {
18 | super(context);
19 | init(context);
20 | }
21 |
22 | public LinearMainLayout(Context context, AttributeSet attrs) {
23 | super(context, attrs);
24 | init(context);
25 | }
26 |
27 | WidgetTvViewBring mWidgetTvViewBring;
28 |
29 | private void init(Context context) {
30 | this.setChildrenDrawingOrderEnabled(true);
31 | mWidgetTvViewBring = new WidgetTvViewBring(this);
32 | }
33 |
34 | @Override
35 | public void bringChildToFront(View child) {
36 | mWidgetTvViewBring.bringChildToFront(this, child);
37 | }
38 |
39 | @Override
40 | protected int getChildDrawingOrder(int childCount, int i) {
41 | return mWidgetTvViewBring.getChildDrawingOrder(childCount, i);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/view/ListViewTV.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.view;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.util.AttributeSet;
6 | import android.view.View;
7 | import android.widget.ListView;
8 |
9 | public class ListViewTV extends ListView {
10 |
11 | public ListViewTV(Context context) {
12 | this(context, null);
13 | }
14 |
15 | public ListViewTV(Context context, AttributeSet attrs) {
16 | super(context, attrs);
17 | init(context, attrs);
18 | }
19 |
20 | /**
21 | * 崩溃了.
22 | */
23 | @Override
24 | protected void dispatchDraw(Canvas canvas) {
25 | try {
26 | super.dispatchDraw(canvas);
27 | } catch (Exception e) {
28 | e.printStackTrace();
29 | }
30 | }
31 |
32 | @Override
33 | public boolean isInTouchMode() {
34 | return !(hasFocus() && !super.isInTouchMode());
35 | }
36 |
37 | WidgetTvViewBring mWidgetTvViewBring;
38 |
39 | private void init(Context context, AttributeSet attrs) {
40 | this.setChildrenDrawingOrderEnabled(true);
41 | mWidgetTvViewBring = new WidgetTvViewBring(this);
42 | }
43 |
44 | @Override
45 | public void bringChildToFront(View child) {
46 | mWidgetTvViewBring.bringChildToFront(this, child);
47 | }
48 |
49 | @Override
50 | protected int getChildDrawingOrder(int childCount, int i) {
51 | return mWidgetTvViewBring.getChildDrawingOrder(childCount, i);
52 | }
53 |
54 | public void setDefualtSelect(int pos) {
55 | requestFocusFromTouch();
56 | setSelection(pos);
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/view/OpenTabHost.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.view;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import com.open.androidtvwidget.R;
7 | import com.open.androidtvwidget.adapter.BaseTabTitleAdapter;
8 |
9 | import android.content.Context;
10 | import android.graphics.Color;
11 | import android.util.AttributeSet;
12 | import android.view.LayoutInflater;
13 | import android.view.View;
14 | import android.widget.TabHost;
15 | import android.widget.TabWidget;
16 |
17 | /**
18 | * 标题栏控
19 | * 你也可以不使用,或者用button,用TextView都可以,
20 | * 不过你需要处理下焦点问题.
21 | * TextView 可能要设置下 android:focusable="true"
22 | * 可以使用 android:nextFocusRight 来控制焦点.
23 | *
24 | * @author hailongqiu
25 | *
26 | */
27 | public class OpenTabHost extends TabHost {
28 |
29 | public OpenTabHost(Context context) {
30 | this(context, null);
31 | }
32 |
33 | public OpenTabHost(Context context, AttributeSet attrs) {
34 | super(context, attrs);
35 | init(context, attrs);
36 | }
37 |
38 | private Context mContext;
39 | private TabWidget mTabWidget; // 标题栏.
40 | private BaseTabTitleAdapter mAdapter;
41 | private List mCacheView = new ArrayList();
42 | private OnTabSelectListener mOnTabSelectListener;
43 |
44 | private void init(Context context, AttributeSet attrs) {
45 | this.mContext = context;
46 | LayoutInflater.from(context).inflate(R.layout.tabhost_title_head, this, true);
47 | mTabWidget = (TabWidget) findViewById(android.R.id.tabs);
48 | setup();
49 | mTabWidget.setStripEnabled(false);
50 | initViewEvents();
51 | this.setBackgroundColor(Color.TRANSPARENT);
52 | }
53 |
54 | private void initViewEvents() {
55 | setOnTabChangedListener(new OnTabChangeListener() {
56 | @Override
57 | public void onTabChanged(String tabId) {
58 | int position = getCurrentTab();
59 | OnTabSelectListener cb = mOnTabSelectListener;
60 | if (cb != null) {
61 | TabWidget tw = getTabWidget();
62 | View titleWidget = tw.getChildTabViewAt(position);
63 | cb.onTabSelect(OpenTabHost.this, titleWidget, position);
64 | }
65 | }
66 | });
67 | }
68 |
69 | public void setOnTabSelectListener(OnTabSelectListener cb) {
70 | this.mOnTabSelectListener = cb;
71 | }
72 |
73 | public OnTabSelectListener getOnTabSelectListener() {
74 | return this.mOnTabSelectListener;
75 | }
76 |
77 | public void addTabWidget(TabSpec tabSpec) {
78 | tabSpec.setContent(new DummyTabFactory(mContext));
79 | this.addTab(tabSpec);
80 | }
81 |
82 | class DummyTabFactory implements TabContentFactory {
83 | private final Context mContext;
84 |
85 | public DummyTabFactory(Context context) {
86 | this.mContext = context;
87 | }
88 |
89 | /**
90 | * 创建一个空的Content.
91 | */
92 | @Override
93 | public View createTabContent(String tag) {
94 | View v = new View(mContext);
95 | v.setMinimumWidth(0);
96 | v.setMinimumHeight(0);
97 | return v;
98 | }
99 | }
100 |
101 | public void setAdapter(BaseTabTitleAdapter adapter) {
102 | mCacheView.clear();
103 | clearAllTabs();
104 | this.mAdapter = adapter;
105 | if (this.mAdapter != null) {
106 | int count = this.mAdapter.getCount();
107 | if (count > 0) {
108 | for (int i = 0; i < count; i++) {
109 | View titleView = this.mAdapter.getView(i, null, this);
110 | mCacheView.add(titleView);
111 | TabSpec tabSpec = this.newTabSpec(i + "").setIndicator(titleView);
112 | this.addTabWidget(tabSpec);
113 | }
114 | requestLayout();
115 | }
116 | }
117 | }
118 |
119 | public List getAllTitleView() {
120 | return this.mCacheView;
121 | }
122 |
123 | public View getTitleViewIndexAt(int index) {
124 | return this.mCacheView.get(index);
125 | }
126 |
127 | public View getTitleViewIdAt(int index) {
128 | return this.mCacheView.get(index).findViewById(this.mAdapter.getTitleWidgetID(index));
129 | }
130 |
131 | public interface OnTabSelectListener {
132 | public void onTabSelect(OpenTabHost openTabHost, View titleWidget, int postion);
133 | }
134 |
135 | /**
136 | * 修复鼠标点击,按数字键会丢失焦点的问题
137 | * 倾听者(344176791) 修复.
138 | */
139 | @Override
140 | public void onTouchModeChanged(boolean isInTouchMode) {
141 | }
142 |
143 | }
144 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/view/RelativeMainLayout.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.view;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 | import android.widget.RelativeLayout;
7 |
8 | /**
9 | * 如果有控件放大被挡住,可以使用 RelativeMainLayout,
10 | * 它继承于 LinearLayout.
11 | * 使用方式和LinerLayout是一样的
12 | * @author hailongqiu
13 | *
14 | */
15 | public class RelativeMainLayout extends RelativeLayout {
16 |
17 | public RelativeMainLayout(Context context) {
18 | super(context);
19 | init(context);
20 | }
21 |
22 | public RelativeMainLayout(Context context, AttributeSet attrs) {
23 | super(context, attrs);
24 | init(context);
25 | }
26 |
27 | WidgetTvViewBring mWidgetTvViewBring;
28 |
29 | private void init(Context context) {
30 | this.setChildrenDrawingOrderEnabled(true);
31 | mWidgetTvViewBring = new WidgetTvViewBring(this);
32 | }
33 |
34 | @Override
35 | public void bringChildToFront(View child) {
36 | mWidgetTvViewBring.bringChildToFront(this, child);
37 | }
38 |
39 | @Override
40 | protected int getChildDrawingOrder(int childCount, int i) {
41 | return mWidgetTvViewBring.getChildDrawingOrder(childCount, i);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/view/SmoothHorizontalScrollView.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.view;
2 |
3 | import com.open.androidtvwidget.R;
4 |
5 | import android.content.Context;
6 | import android.graphics.Rect;
7 | import android.util.AttributeSet;
8 | import android.widget.HorizontalScrollView;
9 |
10 | /**
11 | * 当你使用滚动窗口焦点错乱的时候,就可以使用这个控件.
12 | *
13 | * 使用方法和滚动窗口是一样的,具体查看DEMO吧.
14 | *
15 | * 如果想改变滚动的系数,R.dimen.fading_edge
16 | *
17 | *
18 | * @author hailongqiu
19 | */
20 | public class SmoothHorizontalScrollView extends HorizontalScrollView {
21 | final String TAG = "SmoothHorizontalScrollView";
22 |
23 | private int mFadingEdge;
24 |
25 | public SmoothHorizontalScrollView(Context context) {
26 | this(context, null, 0);
27 | }
28 |
29 | public SmoothHorizontalScrollView(Context context, AttributeSet attrs) {
30 | this(context, attrs, 0);
31 | }
32 |
33 | public SmoothHorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
34 | super(context, attrs, defStyle);
35 | }
36 |
37 | public void setFadingEdge(int fadingEdge) {
38 | this.mFadingEdge = fadingEdge;
39 | }
40 |
41 | @Override
42 | protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
43 | if (getChildCount() == 0)
44 | return 0;
45 |
46 | int width = getWidth();
47 | int screenLeft = getScrollX();
48 | int screenRight = screenLeft + width;
49 |
50 | int fadingEdge = mFadingEdge > 0 ? mFadingEdge : this.getResources().getDimensionPixelSize(R.dimen.fading_edge);
51 |
52 | // leave room for left fading edge as long as rect isn't at very left
53 | if (rect.left > 0) {
54 | screenLeft += fadingEdge;
55 | }
56 |
57 | // leave room for right fading edge as long as rect isn't at very right
58 | if (rect.right < getChildAt(0).getWidth()) {
59 | screenRight -= fadingEdge;
60 | }
61 |
62 | int scrollXDelta = 0;
63 |
64 | if (rect.right > screenRight && rect.left > screenLeft) {
65 | // need to move right to get it in view: move right just enough so
66 | // that the entire rectangle is in view (or at least the first
67 | // screen size chunk).
68 |
69 | if (rect.width() > width) {
70 | // just enough to get screen size chunk on
71 | scrollXDelta += (rect.left - screenLeft);
72 | } else {
73 | // get entire rect at right of screen
74 | scrollXDelta += (rect.right - screenRight);
75 | }
76 |
77 | // make sure we aren't scrolling beyond the end of our content
78 | int right = getChildAt(0).getRight();
79 | int distanceToRight = right - screenRight;
80 | scrollXDelta = Math.min(scrollXDelta, distanceToRight);
81 |
82 | } else if (rect.left < screenLeft && rect.right < screenRight) {
83 | // need to move right to get it in view: move right just enough so
84 | // that
85 | // entire rectangle is in view (or at least the first screen
86 | // size chunk of it).
87 |
88 | if (rect.width() > width) {
89 | // screen size chunk
90 | scrollXDelta -= (screenRight - rect.right);
91 | } else {
92 | // entire rect at left
93 | scrollXDelta -= (screenLeft - rect.left);
94 | }
95 |
96 | // make sure we aren't scrolling any further than the left our
97 | // content
98 | scrollXDelta = Math.max(scrollXDelta, -getScrollX());
99 | }
100 | return scrollXDelta;
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/view/SmoothVorizontalScrollView.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.view;
2 |
3 | import com.open.androidtvwidget.R;
4 |
5 | import android.content.Context;
6 | import android.graphics.Rect;
7 | import android.util.AttributeSet;
8 | import android.widget.ScrollView;
9 |
10 | /**
11 | * 当你使用滚动窗口焦点错乱的时候,就可以使用这个控件.
12 | *
13 | * 使用方法和滚动窗口是一样的,具体查看DEMO吧.
14 | *
15 | * 如果想改变滚动的系数,R.dimen.fading_edge
16 | *
17 | *
18 | * @author hailongqiu
19 | */
20 | public class SmoothVorizontalScrollView extends ScrollView {
21 |
22 | public SmoothVorizontalScrollView(Context context) {
23 | super(context, null, 0);
24 | }
25 |
26 | private int mFadingEdge;
27 |
28 | public SmoothVorizontalScrollView(Context context, AttributeSet attrs) {
29 | super(context, attrs, 0);
30 | }
31 |
32 | public SmoothVorizontalScrollView(Context context, AttributeSet attrs, int defStyle) {
33 | super(context, attrs, defStyle);
34 | }
35 |
36 | public void setFadingEdge(int fadingEdge) {
37 | this.mFadingEdge = fadingEdge;
38 | }
39 |
40 | @Override
41 | protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
42 | if (getChildCount() == 0)
43 | return 0;
44 | int height = getHeight();
45 | int screenTop = getScrollY();
46 | int screenBottom = screenTop + height;
47 | int fadingEdge = mFadingEdge > 0 ? mFadingEdge : this.getResources().getDimensionPixelSize(R.dimen.fading_edge);
48 | if (rect.top > 0) {
49 | screenTop += fadingEdge;
50 | }
51 | if (rect.bottom < getChildAt(0).getHeight()) {
52 | screenBottom -= fadingEdge;
53 | }
54 | //
55 | int scrollYDelta = 0;
56 | if (rect.bottom > screenBottom && rect.top > screenTop) {
57 | if (rect.height() > height) {
58 | scrollYDelta += (rect.top - screenTop);
59 | } else {
60 | scrollYDelta += (rect.bottom - screenBottom);
61 | }
62 | int bottom = getChildAt(0).getBottom();
63 | int distanceToBottom = bottom - screenBottom;
64 | scrollYDelta = Math.min(scrollYDelta, distanceToBottom);
65 | } else if (rect.top < screenTop && rect.bottom < screenBottom) {
66 | if (rect.height() > height) {
67 | scrollYDelta -= (screenBottom - rect.bottom);
68 | } else {
69 | scrollYDelta -= (screenTop - rect.top);
70 | }
71 | scrollYDelta = Math.max(scrollYDelta, -getScrollY());
72 | }
73 | return scrollYDelta;
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/view/TextViewWithTTF.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.view;
2 |
3 |
4 | import java.util.HashMap;
5 |
6 | import com.open.androidtvwidget.R;
7 |
8 | import android.content.Context;
9 | import android.content.res.TypedArray;
10 | import android.graphics.Typeface;
11 | import android.util.AttributeSet;
12 | import android.widget.TextView;
13 |
14 | /**
15 | * 一个自定义的TextView控件.
16 | * 加载 /system/font/** 下面的字库.
17 | * @author hailongqiu
18 | *
19 | */
20 | public class TextViewWithTTF extends TextView {
21 |
22 | private static final TypeFaceMgr SFontMgr = new TypeFaceMgr();
23 |
24 | public TextViewWithTTF(Context context) {
25 | super(context);
26 | }
27 |
28 | public TextViewWithTTF(Context context, AttributeSet attrs) {
29 | super(context, attrs);
30 |
31 | TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.TextViewWithTTF);
32 | setTypeface(SFontMgr.getTypeface(array.getString(R.styleable.TextViewWithTTF_ttf_name)));
33 | array.recycle();
34 | }
35 |
36 |
37 |
38 | public TextViewWithTTF(Context context, String aTTFName)
39 | {
40 | super(context);
41 | setTypeface(SFontMgr.getTypeface(aTTFName));
42 | }
43 |
44 | public void setFont(String aTTFName) {
45 | setTypeface(SFontMgr.getTypeface(aTTFName));
46 | }
47 | }
48 |
49 |
50 | class TypeFaceMgr
51 | {
52 | HashMap mTypefaces;
53 | public TypeFaceMgr()
54 | {
55 | mTypefaces = new HashMap();
56 | }
57 | public Typeface getTypeface(String aTTFName)
58 | {
59 | if(mTypefaces.containsKey(aTTFName))
60 | {
61 | return mTypefaces.get(aTTFName);
62 | }
63 | else
64 | {
65 | Typeface font;
66 | try
67 | {
68 | font = Typeface.createFromFile("/system/fonts/"+aTTFName);
69 | }
70 | catch (Exception e)
71 | {
72 | e.printStackTrace();
73 | return null;
74 | }
75 |
76 | mTypefaces.put(aTTFName, font);
77 | return font;
78 | }
79 | }
80 | }
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/view/ViewPagerTV.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.view;
2 |
3 | import android.content.Context;
4 | import android.support.v4.view.ViewPager;
5 | import android.util.AttributeSet;
6 |
7 | public class ViewPagerTV extends ViewPager {
8 |
9 | public ViewPagerTV(Context context) {
10 | super(context);
11 | }
12 |
13 | public ViewPagerTV(Context context, AttributeSet attrs) {
14 | super(context, attrs);
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/java/com/open/androidtvwidget/view/WidgetTvViewBring.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget.view;
2 |
3 | import android.view.View;
4 | import android.view.ViewGroup;
5 |
6 | /**
7 | * 让ViewGroup中的控件在最上层
8 | * ListView, GridView, ViewGroup中使用. 想要置顶的子控件,不要忘记调用 bringToFront() 噢.
9 | *
10 | * @author hailongqiu
11 | *
12 | */
13 | public class WidgetTvViewBring {
14 |
15 | private int position = 0;
16 |
17 | public WidgetTvViewBring() {
18 | }
19 |
20 | public WidgetTvViewBring(ViewGroup vg) {
21 | vg.setClipChildren(false);
22 | vg.setClipToPadding(false);
23 | // vg.setChildrenDrawingOrderEnabled(true);
24 | }
25 |
26 | public void bringChildToFront(ViewGroup vg, View child) {
27 | position = vg.indexOfChild(child);
28 | if (position != -1) {
29 | vg.postInvalidate();
30 | }
31 | }
32 |
33 | /**
34 | * 此函数 dispatchDraw 中调用.
35 | * 原理就是和最后一个要绘制的view,交换了位置.
36 | * 因为dispatchDraw最后一个绘制的view是在最上层的.
37 | * 这样就避免了使用 bringToFront 导致焦点错乱问题.
38 | */
39 | public int getChildDrawingOrder(int childCount, int i) {
40 | if (position != -1) {
41 | if (i == childCount - 1)
42 | return position;
43 | if (i == position)
44 | return childCount - 1;
45 | }
46 | return i;
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/res/drawable/nocolor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/FrozenFreeFall/Android-tv-widget/48a396211370e4d9c11072488dbca5f0e11882a7/Demo/androidtvwidget/src/main/res/drawable/nocolor.png
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/res/layout/lb_content_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/res/layout/lb_item_container.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/res/layout/list_menu_item_icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/res/layout/list_menu_item_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
11 |
12 |
13 |
14 |
26 |
27 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/res/layout/open_menu_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/res/layout/softkey_layout_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
16 |
17 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/res/layout/tabhost_title_head.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
17 |
18 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 80dp
6 |
7 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AndroidTvWidget
3 |
4 |
--------------------------------------------------------------------------------
/Demo/androidtvwidget/src/test/java/com/open/androidtvwidget/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.open.androidtvwidget;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/Demo/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/Demo/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion '23.0.2'
6 |
7 | defaultConfig {
8 | applicationId "com.open.demo"
9 | minSdkVersion 15
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(include: ['*.jar'], dir: 'libs')
24 | testCompile 'junit:junit:4.12'
25 | compile 'com.android.support:appcompat-v7:23.1.1'
26 | compile project(':androidtvwidget')
27 | }
28 |
--------------------------------------------------------------------------------
/Demo/app/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 F:\dev\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 |
--------------------------------------------------------------------------------
/Demo/app/src/androidTest/java/com/open/demo/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.open.demo;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/Demo/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
14 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Demo/app/src/main/java/com/open/demo/DemoListViewActivity.java:
--------------------------------------------------------------------------------
1 | package com.open.demo;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import com.open.androidtvwidget.bridge.EffectNoDrawBridge;
7 | import com.open.androidtvwidget.utils.Utils;
8 | import com.open.androidtvwidget.view.ListViewTV;
9 | import com.open.androidtvwidget.view.MainUpView;
10 |
11 | import android.app.Activity;
12 | import android.graphics.Rect;
13 | import android.os.Bundle;
14 | import android.os.Handler;
15 | import android.os.Message;
16 | import android.view.LayoutInflater;
17 | import android.view.View;
18 | import android.view.ViewGroup;
19 | import android.widget.AdapterView;
20 | import android.widget.AdapterView.OnItemClickListener;
21 | import android.widget.AdapterView.OnItemSelectedListener;
22 | import android.widget.BaseAdapter;
23 | import android.widget.ListView;
24 | import android.widget.TextView;
25 | import android.widget.Toast;
26 |
27 | public class DemoListViewActivity extends Activity {
28 |
29 | private static final String TAG = "DemoListViewActivity";
30 |
31 | private List data;
32 | private MainUpView mainUpView1;
33 | private LayoutInflater mInflater;
34 | private View mOldView;
35 | private ListViewTV listView;
36 |
37 | @Override
38 | protected void onCreate(Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 | setContentView(R.layout.demo_list_view);
41 | this.mInflater = LayoutInflater.from(getApplicationContext());
42 | listView = (ListViewTV) findViewById(R.id.listview);
43 | mainUpView1 = (MainUpView) findViewById(R.id.mainUpView1);
44 | // 默认是 OpenEff...,建议使用 NoDraw... ...
45 | mainUpView1.setEffectBridge(new EffectNoDrawBridge());
46 | EffectNoDrawBridge bridget = (EffectNoDrawBridge) mainUpView1.getEffectBridge();
47 | bridget.setTranDurAnimTime(200);
48 | //
49 | mainUpView1.setUpRectResource(R.drawable.white_light_10); // 设置移动边框的图片.
50 | mainUpView1.setDrawUpRectPadding(new Rect(25, 25, 23, 23)); // 边框图片设置间距.
51 | //
52 | initData();
53 | //
54 | listView.setAdapter(new DemoAdapter());
55 | //
56 | listView.setOnItemSelectedListener(new OnItemSelectedListener() {
57 | @Override
58 | public void onItemSelected(AdapterView> parent, View view, int position, long id) {
59 | if (view != null) {
60 | view.bringToFront();
61 | mainUpView1.setFocusView(view, mOldView, 1.2f);
62 | mOldView = view;
63 | }
64 | }
65 |
66 | @Override
67 | public void onNothingSelected(AdapterView> parent) {
68 | }
69 | });
70 | listView.setOnItemClickListener(new OnItemClickListener() {
71 | @Override
72 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
73 | Toast.makeText(getApplicationContext(), "position : " + position, Toast.LENGTH_LONG).show();
74 | }
75 | });
76 | // 延时请求其它位置的item.
77 | Handler handler = new Handler() {
78 | @Override
79 | public void handleMessage(Message msg) {
80 | listView.setDefualtSelect(2);
81 | }
82 | };
83 | handler.sendMessageDelayed(handler.obtainMessage(), 188);
84 | }
85 |
86 | public void initData() {
87 | data = new ArrayList();
88 | for (int i = 0; i < 105; i++) {
89 | String text = "item" + i;
90 | data.add(text);
91 | }
92 | }
93 |
94 | public class DemoAdapter extends BaseAdapter {
95 |
96 | @Override
97 | public int getCount() {
98 | return data.size();
99 | }
100 |
101 | @Override
102 | public Object getItem(int position) {
103 | return data.get(position);
104 | }
105 |
106 | @Override
107 | public long getItemId(int position) {
108 | return position;
109 | }
110 |
111 | @Override
112 | public View getView(int position, View convertView, ViewGroup parent) {
113 | ViewHolder holder = null;
114 | if (convertView == null) {
115 | holder = new ViewHolder();
116 | convertView = mInflater.inflate(R.layout.item_listview, null);
117 | holder.title = (TextView) convertView.findViewById(R.id.textView);
118 | convertView.setTag(holder);
119 | } else {
120 | holder = (ViewHolder) convertView.getTag();
121 | }
122 | holder.title.setText(data.get(position));
123 | return convertView;
124 | }
125 |
126 | public class ViewHolder {
127 | public TextView title;
128 | }
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/Demo/app/src/main/java/com/open/demo/DemoMenuActivity.java:
--------------------------------------------------------------------------------
1 | package com.open.demo;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.graphics.drawable.Drawable;
6 | import android.os.Bundle;
7 | import android.support.v7.widget.DefaultItemAnimator;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.view.View;
10 | import android.view.View.OnClickListener;
11 |
12 | import com.open.androidtvwidget.bridge.OpenEffectBridge;
13 | import com.open.androidtvwidget.menu.OpenMenu;
14 | import com.open.androidtvwidget.menu.OpenMenuImpl;
15 | import com.open.androidtvwidget.menu.OpenMenuItem;
16 | import com.open.androidtvwidget.leanback.recycle.RecyclerViewTV;
17 | import com.open.androidtvwidget.utils.OPENLOG;
18 | import com.open.androidtvwidget.view.MainUpView;
19 | import com.open.androidtvwidget.leanback.adapter.GeneralAdapter;
20 | import com.open.demo.menu.TreeMenuPresenter;
21 |
22 | /**
23 | * 菜单DEMO测试.
24 | *
25 | * @author hailongqiu
26 | */
27 | public class DemoMenuActivity extends Activity implements OnClickListener {
28 |
29 | private Context mContext;
30 | OpenMenu mOpenMenu;
31 | RecyclerViewTV mRecyclerView;
32 |
33 | public DemoMenuActivity() {
34 | OPENLOG.initTag("hailongqiu", true); // 测试LOG输出.
35 | }
36 |
37 | @Override
38 | protected void onCreate(Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 | setContentView(R.layout.demo_menu_activity);
41 | // findViewById(R.id.content11).setBackgroundResource(R.drawable.main_bg);
42 | findViewById(R.id.button1).setOnClickListener(this);
43 | findViewById(R.id.button2).setOnClickListener(this);
44 | mContext = DemoMenuActivity.this;
45 | initAllMenu();
46 | }
47 |
48 | private Drawable getResources(int id) {
49 | return getResources().getDrawable(id);
50 | }
51 |
52 | private void initAllMenu() {
53 | // 主菜单.
54 | mOpenMenu = new OpenMenuImpl();
55 | final OpenMenuItem menuItem1 = mOpenMenu.add("菜单1");
56 | menuItem1.setIconRes(R.drawable.ic_launcher).setId(R.id.menu_1_1).setChecked(true);
57 | mOpenMenu.add("菜单2").setIconRes(R.drawable.ic_launcher).setId(R.id.menu_1_2);
58 | mOpenMenu.add("菜单3").setIconRes(R.drawable.ic_launcher).setId(R.id.menu_1_3);
59 | mOpenMenu.add("菜单4").setIconRes(R.drawable.ic_launcher).setId(R.id.menu_1_4);
60 | mOpenMenu.add("菜单5").setIconRes(R.drawable.ic_launcher).setId(R.id.menu_1_5);
61 | mOpenMenu.add("菜单6").setIconRes(R.drawable.ic_launcher);
62 | mOpenMenu.add("菜单7").setIconRes(R.drawable.ic_launcher);
63 | // 菜单1的子菜单.
64 | OpenMenu subMenu1 = new OpenMenuImpl();
65 | subMenu1.add("菜单1-1");
66 | subMenu1.add("菜单1-2").setIconRes(R.drawable.ic_launcher);
67 | subMenu1.add("菜单1-3");
68 | // 菜单2的子菜单.
69 | OpenMenu subMenu2 = new OpenMenuImpl();
70 | subMenu2.add("菜单5-1");
71 | subMenu2.add("菜单5-2");
72 | subMenu2.add("菜单5-3");
73 | // 菜单1-2 添加子菜单(第三级菜单).
74 | OpenMenu subMenu1_2 = new OpenMenuImpl();
75 | subMenu1_2.add("菜单1-2-1");
76 | subMenu1_2.add("菜单1-2-2");
77 | subMenu1_2.add("菜单1-2-3");
78 | //
79 | OpenMenu subMenu1_2_1 = new OpenMenuImpl();
80 | subMenu1_2_1.add("菜单1-2-1-1");
81 | subMenu1_2_1.add("菜单1-2-1-2");
82 | subMenu1_2.addSubMenu(0, subMenu1_2_1); // 三级菜单添加四级菜单.
83 | // 添加子菜单.
84 | menuItem1.addSubMenu(subMenu1); // 一级菜单的menuItem1 添加二级菜单.
85 | mOpenMenu.addSubMenu(4, subMenu2); // 一级菜单添加二级菜单.
86 | subMenu1.addSubMenu(1, subMenu1_2); // 二级菜单添加三级菜单.
87 | // 输出菜单数据.
88 | mOpenMenu.toString();
89 | // test menu.
90 | final MainUpView mainUpView = new MainUpView(mContext);
91 | mainUpView.setEffectBridge(new OpenEffectBridge());
92 | mainUpView.setUpRectResource(R.drawable.white_light_10);
93 | mRecyclerView = (RecyclerViewTV) findViewById(R.id.recyclerView_menu);
94 | GeneralAdapter menuAdapter = new GeneralAdapter(new TreeMenuPresenter(mRecyclerView, mOpenMenu));
95 | mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext));
96 | mRecyclerView.setAdapter(menuAdapter);
97 | mRecyclerView.setItemAnimator(new DefaultItemAnimator());
98 | mRecyclerView.setOnItemListener(new RecyclerViewTV.OnItemListener() {
99 | @Override
100 | public void onItemPreSelected(RecyclerViewTV parent, View itemView, int position) {
101 | mainUpView.setUnFocusView(itemView);
102 | }
103 | @Override
104 | public void onItemSelected(RecyclerViewTV parent, View itemView, int position) {
105 | mainUpView.setFocusView(itemView, 1.0f);
106 | }
107 | @Override
108 | public void onReviseFocusFollow(RecyclerViewTV parent, View itemView, int position) {
109 | }
110 | });
111 | }
112 |
113 | @Override
114 | public void onClick(View v) {
115 | int id = v.getId();
116 | switch (id) {
117 | case R.id.button1:
118 | mOpenMenu.showMenu();
119 | break;
120 | case R.id.button2:
121 | mOpenMenu.hideMenu();
122 | break;
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/Demo/app/src/main/java/com/open/demo/MenuAnimationUtils.java:
--------------------------------------------------------------------------------
1 | package com.open.demo;
2 |
3 | import android.content.Context;
4 | import android.view.animation.AlphaAnimation;
5 | import android.view.animation.Animation;
6 | import android.view.animation.AnimationSet;
7 | import android.view.animation.LayoutAnimationController;
8 | import android.view.animation.RotateAnimation;
9 | import android.view.animation.TranslateAnimation;
10 |
11 | /**
12 | * Created by hailongqiu on 2016/6/3.
13 | */
14 | public class MenuAnimationUtils {
15 |
16 | /**
17 | * 从左到右显示菜单.
18 | */
19 | public static Animation showAnimation() {
20 | Animation animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, -1.0f, Animation.RELATIVE_TO_SELF,
21 | 0.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
22 | animation.setDuration(1000);
23 | return animation;
24 | }
25 |
26 | /**
27 | * 从右到左隐藏菜单.
28 | */
29 | public static Animation hideAnimation() {
30 | Animation animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF,
31 | -1.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
32 | animation.setDuration(500);
33 | return animation;
34 | }
35 |
36 | /**
37 | * 加载动画.
38 | */
39 | @SuppressWarnings("ResourceType")
40 | public static LayoutAnimationController loadAnimation(Context context) {
41 | /*
42 | * 创建动画的集合
43 | */
44 | AnimationSet set = new AnimationSet(false);
45 | Animation animation;
46 | /*
47 | * 创建旋转动画
48 | */
49 | animation = new RotateAnimation(180, 10);
50 | animation.setDuration(1000);
51 | set.addAnimation(animation);
52 |
53 | LayoutAnimationController controller = new LayoutAnimationController(set, 1);
54 | controller.setInterpolator(context, android.R.anim.accelerate_interpolator);
55 | controller.setAnimation(set);
56 | return controller;
57 | }
58 |
59 | /**
60 | * 加载动画2.
61 | */
62 | public static LayoutAnimationController loadAnimation2() {
63 | int duration = 300;
64 | AnimationSet set = new AnimationSet(true);
65 |
66 | Animation animation = new AlphaAnimation(0.0f, 1.0f);
67 | animation.setDuration(duration);
68 | set.addAnimation(animation);
69 |
70 | animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
71 | Animation.RELATIVE_TO_SELF, -1.0f, Animation.RELATIVE_TO_SELF, 0.0f);
72 | animation.setDuration(duration);
73 | set.addAnimation(animation);
74 |
75 | LayoutAnimationController controller = new LayoutAnimationController(set, 0.5f);
76 | controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
77 | return controller;
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/Demo/app/src/main/java/com/open/demo/Rotate3dAnimation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2007 The Android Open Source Project
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.open.demo;
18 |
19 | import android.view.animation.Animation;
20 | import android.view.animation.Transformation;
21 | import android.graphics.Camera;
22 | import android.graphics.Matrix;
23 |
24 | /**
25 | * 一个在指定了两个角度的在Y轴旋转的动画类.
26 | * 这个类也添加了一个z轴的属性用来提高效果.
27 | * An animation that rotates the view on the Y axis between two specified angles.
28 | * This animation also adds a translation on the Z axis (depth) to improve the effect.
29 | */
30 | public class Rotate3dAnimation extends Animation {
31 | private final float mFromDegrees;
32 | private final float mToDegrees;
33 | private final float mCenterX;
34 | private final float mCenterY;
35 | private final float mDepthZ;
36 | private final boolean mReverse;
37 | private Camera mCamera;
38 |
39 | /**
40 | * 在Y轴创建了一个新的3D的旋转动画,这个旋转动画定义了它的开始角度和结束角度,
41 | * 两个角度的单位都是度数,这个旋转动画围绕在2D空间的中心点执行.
42 | * 你可以用X轴坐标(叫做centerX)和Y轴(叫做centerY)坐标来定义这个中心点.
43 | * 当动画开始时,对于z轴(深度)的转换就会被执行.转换的长度和转换正向反向都可以指定.
44 | * Creates a new 3D rotation on the Y axis. The rotation is defined by its
45 | * start angle and its end angle. Both angles are in degrees. The rotation
46 | * is performed around a center point on the 2D space, definied by a pair
47 | * of X and Y coordinates, called centerX and centerY. When the animation
48 | * starts, a translation on the Z axis (depth) is performed. The length
49 | * of the translation can be specified, as well as whether the translation
50 | * should be reversed in time.
51 | *
52 | * @param fromDegrees the start angle of the 3D rotation 开始的角度
53 | * @param toDegrees the end angle of the 3D rotation 结束的角度
54 | * @param centerX the X center of the 3D rotation 中心点X轴坐标
55 | * @param centerY the Y center of the 3D rotation 中心点Y轴坐标
56 | * @param reverse true if the translation should be reversed, false otherwise true表示反向,false表示正向
57 | */
58 | public Rotate3dAnimation(float fromDegrees, float toDegrees,
59 | float centerX, float centerY, float depthZ, boolean reverse) {
60 | mFromDegrees = fromDegrees;
61 | mToDegrees = toDegrees;
62 | mCenterX = centerX;
63 | mCenterY = centerY;
64 | mDepthZ = depthZ;
65 | mReverse = reverse;
66 | }
67 |
68 | @Override
69 | public void initialize(int width, int height, int parentWidth, int parentHeight) {
70 | super.initialize(width, height, parentWidth, parentHeight);
71 | mCamera = new Camera();
72 | }
73 |
74 | @Override
75 | protected void applyTransformation(float interpolatedTime, Transformation t) {
76 | final float fromDegrees = mFromDegrees;
77 | float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
78 |
79 | final float centerX = mCenterX;
80 | final float centerY = mCenterY;
81 | final Camera camera = mCamera;
82 |
83 | final Matrix matrix = t.getMatrix();
84 |
85 | camera.save();
86 | if (mReverse) {
87 | camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
88 | } else {
89 | camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
90 | }
91 | camera.rotateY(degrees);
92 | camera.getMatrix(matrix);
93 | camera.restore();
94 |
95 | matrix.preTranslate(-centerX, -centerY);
96 | matrix.postTranslate(centerX, centerY);
97 | }
98 | }
--------------------------------------------------------------------------------
/Demo/app/src/main/java/com/open/demo/adapter/GridViewHolder.java:
--------------------------------------------------------------------------------
1 | package com.open.demo.adapter;
2 |
3 | import com.open.androidtvwidget.leanback.mode.OpenPresenter;
4 | import com.open.demo.R;
5 |
6 | import android.view.View;
7 | import android.widget.ImageView;
8 | import android.widget.TextView;
9 |
10 | public class GridViewHolder extends OpenPresenter.ViewHolder {
11 |
12 | public ImageView iv;
13 | public TextView tv;
14 | public TextView head_tv;
15 |
16 | public GridViewHolder(View itemView) {
17 | super(itemView);
18 | // iv = (ImageView)itemView.findViewById(R.id.);
19 | tv = (TextView)itemView.findViewById(R.id.textView);
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/Demo/app/src/main/java/com/open/demo/adapter/LeftMenuPresenter.java:
--------------------------------------------------------------------------------
1 | package com.open.demo.adapter;
2 |
3 | import android.view.ViewGroup;
4 | import android.widget.Button;
5 |
6 | import com.open.androidtvwidget.leanback.mode.OpenPresenter;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | /**
12 | * RecyclerView demo 的左侧菜单.
13 | * Created by hailongqiu on 2016/8/24.
14 | */
15 | public class LeftMenuPresenter extends OpenPresenter {
16 |
17 | private List strList = new ArrayList() {
18 | {
19 | add("横向LinerLayout");
20 | add("纵向LinerLayout");
21 | add("横向GridLayout");
22 | add("纵向GridLayout");
23 | add("Leanback demo");
24 | }
25 | };
26 |
27 | @Override
28 | public int getItemCount() {
29 | return strList.size();
30 | }
31 |
32 | @Override
33 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
34 | Button btn = new Button(parent.getContext());
35 | return new ViewHolder(btn);
36 | }
37 |
38 | @Override
39 | public void onBindViewHolder(ViewHolder viewHolder, int position) {
40 | Button btn = (Button) viewHolder.view;
41 | btn.setFocusableInTouchMode(true); // 只是测试鼠标效果.
42 | btn.setFocusable(true);
43 | String str = strList.get(position);
44 | btn.setText(str);
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/Demo/app/src/main/java/com/open/demo/adapter/OpenTabTitleAdapter.java:
--------------------------------------------------------------------------------
1 | package com.open.demo.adapter;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import com.open.androidtvwidget.adapter.BaseTabTitleAdapter;
7 | import com.open.androidtvwidget.view.TextViewWithTTF;
8 | import com.open.demo.R;
9 |
10 | import android.content.Context;
11 | import android.content.res.Resources;
12 | import android.graphics.Typeface;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.widget.LinearLayout;
16 |
17 | public class OpenTabTitleAdapter extends BaseTabTitleAdapter {
18 | private List titleList = new ArrayList();
19 |
20 | public OpenTabTitleAdapter() {
21 | titleList.add("推荐");
22 | titleList.add("电影");
23 | titleList.add("电视剧");
24 | titleList.add("设置");
25 | }
26 |
27 | @Override
28 | public int getCount() {
29 | return titleList.size();
30 | }
31 |
32 | /**
33 | * 为何要设置ID标识。
34 | * 因为PAGE页面中的ITEM如果向上移到标题栏,
35 | * 它会查找最近的,你只需要在布局中设置
36 | * android:nextFocusUp="@+id/title_bar1"
37 | * 就可以解决焦点问题哦.
38 | */
39 | private List ids = new ArrayList() {
40 | {
41 | add(R.id.title_bar1);
42 | add(R.id.title_bar2);
43 | add(R.id.title_bar3);
44 | add(R.id.title_bar4);
45 | }
46 | };
47 |
48 | @Override
49 | public Integer getTitleWidgetID(int pos) {
50 | return ids.get(pos);
51 | }
52 |
53 | @Override
54 | public View getView(int position, View convertView, ViewGroup parent) {
55 | parent.getContext();
56 | String title = titleList.get(position);
57 | if (convertView == null) {
58 | convertView = newTabIndicator(parent.getContext(), title, false);
59 | convertView.setId(ids.get(position)); // 设置ID.
60 | } else {
61 | // ... ...
62 | }
63 | return convertView;
64 | }
65 |
66 | /**
67 | * 这里只是demo,你可以设置自己的标题栏.
68 | */
69 | private View newTabIndicator(Context context, String tabName, boolean focused) {
70 | final String name = tabName;
71 | View viewC = View.inflate(context, R.layout.tab_view_indicator_item, null);
72 | TextViewWithTTF view = (TextViewWithTTF) viewC.findViewById(R.id.tv_tab_indicator);
73 | LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
74 | ViewGroup.LayoutParams.WRAP_CONTENT);
75 | lp.setMargins(20, 0, 20, 0);
76 | view.setLayoutParams(lp);
77 |
78 | // mTabWidget.setPadding(getResources().getDimensionPixelSize(R.dimen.tab_left_offset),
79 | // 0, 0, 0);
80 |
81 | view.setText(name);
82 |
83 | if (focused == true) {
84 | Resources res = context.getResources();
85 | view.setTextColor(res.getColor(android.R.color.white));
86 | view.setTypeface(null, Typeface.BOLD);
87 | view.requestFocus();
88 | }
89 | return viewC;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/Demo/app/src/main/java/com/open/demo/adapter/RecyclerViewPresenter.java:
--------------------------------------------------------------------------------
1 | package com.open.demo.adapter;
2 |
3 | import android.view.LayoutInflater;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.TextView;
7 |
8 | import com.open.androidtvwidget.leanback.adapter.GeneralAdapter;
9 | import com.open.androidtvwidget.leanback.mode.OpenPresenter;
10 | import com.open.demo.R;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | /**
16 | * 测试.
17 | * Created by hailongqiu on 2016/8/24.
18 | */
19 | public class RecyclerViewPresenter extends OpenPresenter {
20 |
21 | private final List labels;
22 | private GeneralAdapter mAdapter;
23 |
24 | public RecyclerViewPresenter(int count) {
25 | this.labels = new ArrayList(count);
26 | for (int i = 0; i < count; i++) {
27 | labels.add(String.valueOf(i));
28 | }
29 | }
30 |
31 | @Override
32 | public void setAdapter(GeneralAdapter adapter) {
33 | this.mAdapter = adapter;
34 | }
35 |
36 | /**
37 | * 用于数据加载更多测试.
38 | */
39 | public void addDatas(int count) {
40 | int sum = labels.size();
41 | for (int i = sum; i < sum + count; i++) {
42 | labels.add(String.valueOf(i));
43 | }
44 | this.mAdapter.notifyDataSetChanged();
45 | }
46 |
47 | @Override
48 | public int getItemCount() {
49 | return labels.size();
50 | }
51 |
52 | @Override
53 | public int getItemViewType(int position) {
54 | return 0;
55 | }
56 |
57 | @Override
58 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
59 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recyclerview_view, parent, false);
60 | return new GridViewHolder(view);
61 | }
62 |
63 | @Override
64 | public void onBindViewHolder(ViewHolder viewHolder, int position) {
65 | GridViewHolder gridViewHolder = (GridViewHolder) viewHolder;
66 | TextView textView = (TextView) gridViewHolder.tv;
67 | textView.setText("item " + labels.get(position));
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/Demo/app/src/main/java/com/open/demo/menu/TreeMenuPresenter.java:
--------------------------------------------------------------------------------
1 | package com.open.demo.menu;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import com.open.androidtvwidget.leanback.adapter.GeneralAdapter;
9 | import com.open.androidtvwidget.leanback.recycle.RecyclerViewTV;
10 | import com.open.androidtvwidget.leanback.mode.OpenPresenter;
11 | import com.open.androidtvwidget.menu.OpenMenu;
12 | import com.open.androidtvwidget.menu.OpenMenuItem;
13 | import com.open.androidtvwidget.menu.OpenMenuItemView;
14 | import com.open.demo.R;
15 |
16 | import java.util.ArrayList;
17 | import java.util.List;
18 |
19 | /**
20 | * 树级菜单的 Presenter. (mvp)
21 | * Created by hailongqiu on 2016/8/23.
22 | */
23 | public class TreeMenuPresenter extends OpenPresenter {
24 |
25 | private RecyclerViewTV mRecyclerViewTV;
26 | private OpenMenu mOpenMenu;
27 |
28 | public TreeMenuPresenter(RecyclerViewTV recyclerViewTV, OpenMenu openMenu) {
29 | this.mRecyclerViewTV = recyclerViewTV;
30 | this.mOpenMenu = openMenu;
31 | }
32 |
33 | private OpenMenuItem getItemPosition(int position) {
34 | return mOpenMenu.getMenuDatas().get(position);
35 | }
36 |
37 | private void addAll(List list, int pos) {
38 | mOpenMenu.getMenuDatas().addAll(pos, list);
39 | getAdapter().notifyItemRangeInserted(pos, list.size());
40 | }
41 |
42 | private void removeAll(List list, int pos) {
43 | int sizeNum = removeAllSubMenu(list);
44 | getAdapter().notifyItemRangeRemoved(pos, sizeNum);
45 | }
46 |
47 | private int removeAllSubMenu(List list) {
48 | int sizeNum = list.size();
49 | for (OpenMenuItem menuItem : list) {
50 | if (menuItem.hasSubMenu() && menuItem.isShowSubMenu()) {
51 | menuItem.setShowSubMenu(false);
52 | List delSubItems = menuItem.getSubMenu().getMenuDatas();
53 | sizeNum += removeAllSubMenu(delSubItems);
54 | }
55 | }
56 | mOpenMenu.getMenuDatas().removeAll(list);
57 | return sizeNum;
58 | }
59 |
60 | @Override
61 | public int getItemCount() {
62 | return mOpenMenu != null ? mOpenMenu.getMenuDatas().size() : 0;
63 | }
64 |
65 | @Override
66 | public int getItemViewType(int position) {
67 | return 0;
68 | }
69 |
70 | @Override
71 | public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
72 | View rootView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_menu_item_layout, parent, false);
73 | //
74 | OpenPresenter.ViewHolder result = new ContainerViewHolder(rootView);
75 | return result;
76 | }
77 |
78 | @Override
79 | public void onBindViewHolder(ViewHolder viewHolder, int position) {
80 | ArrayList items = mOpenMenu.getMenuDatas();
81 | OpenMenuItem menuItem = items.get(position);
82 | ContainerViewHolder holder = (ContainerViewHolder) viewHolder;
83 | OpenMenuItemView openMenuItemView = (OpenMenuItemView) holder.view;
84 | openMenuItemView.initialize(menuItem);
85 | // 子控件.
86 | if (menuItem.getMenu().getParentMenu() != null) {
87 | RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) openMenuItemView.getLayoutParams();
88 | lp.leftMargin = menuItem.getMenu().getTreeDepth() * 45;
89 | }
90 | // item 单击处理.
91 | mRecyclerViewTV.setOnItemClickListener(new RecyclerViewTV.OnItemClickListener() {
92 | @Override
93 | public void onItemClick(RecyclerViewTV parent, View itemView, int position) {
94 | GeneralAdapter menuAdapter = getAdapter();
95 | OpenMenuItem menuItem = getItemPosition(position);
96 | // 判断是否存在子菜单.
97 | if (menuItem.hasSubMenu()) {
98 | if (!menuItem.isShowSubMenu()) {
99 | // 显示菜单.
100 | addAll(menuItem.getSubMenu().getMenuDatas(), position + 1);
101 | mRecyclerViewTV.scrollToPosition(position + 1);
102 | } else {
103 | // 隐藏菜单.
104 | removeAll(menuItem.getSubMenu().getMenuDatas(), position + 1);
105 | mRecyclerViewTV.scrollToPosition(position + 1);
106 | }
107 | menuItem.setShowSubMenu(!menuItem.isShowSubMenu());
108 | }
109 | }
110 | });
111 | }
112 |
113 | @Override
114 | public void onViewAttachedToWindow(ViewHolder viewHolder) {
115 | }
116 |
117 | @Override
118 | public void onViewDetachedFromWindow(ViewHolder viewHolder) {
119 | }
120 |
121 | @Override
122 | public void onUnbindViewHolder(ViewHolder viewHolder) {
123 | }
124 |
125 | public GeneralAdapter getAdapter() {
126 | return (GeneralAdapter) mRecyclerViewTV.getAdapter();
127 | }
128 |
129 | static class ContainerViewHolder extends OpenPresenter.ViewHolder {
130 | public ContainerViewHolder(View view) {
131 | super(view);
132 | }
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/Demo/app/src/main/java/com/open/demo/mode/ItemHeaderPresenter.java:
--------------------------------------------------------------------------------
1 | package com.open.demo.mode;
2 |
3 | import android.view.LayoutInflater;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.LinearLayout;
7 |
8 | import com.open.androidtvwidget.R;
9 | import com.open.androidtvwidget.leanback.mode.OpenPresenter;
10 | import com.open.androidtvwidget.menu.OpenMenuItemView;
11 |
12 | /**
13 | * 标题头的 Presenter. (test)
14 | * Created by hailongqiu on 2016/8/24.
15 | */
16 | public class ItemHeaderPresenter extends OpenPresenter {
17 |
18 | @Override
19 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
20 | View headview = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_menu_item_layout, parent, false);
21 | return new ItemHeadViewHolder(headview);
22 | }
23 |
24 | @Override
25 | public void onBindViewHolder(ViewHolder viewHolder, Object item) {
26 | LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) viewHolder.view.getLayoutParams();
27 | lp.weight = LinearLayout.LayoutParams.MATCH_PARENT;
28 | ((OpenMenuItemView) viewHolder.view).setTitle((String)item);
29 | }
30 |
31 | static class ItemHeadViewHolder extends OpenPresenter.ViewHolder {
32 | public ItemHeadViewHolder(View view) {
33 | super(view);
34 | }
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/Demo/app/src/main/java/com/open/demo/mode/LeanbackTestData.java:
--------------------------------------------------------------------------------
1 | package com.open.demo.mode;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * Leanaback的测试数据.
8 | * Created by hailongqiu on 2016/9/6.
9 | */
10 | public class LeanbackTestData {
11 |
12 | /**
13 | * Leanback 标题头.
14 | */
15 | public static final String MOVIE_CATEGORY[] = {
16 | "全部软件",
17 | "聊天工具",
18 | "浏览器",
19 | "游戏娱乐",
20 | "网络游戏",
21 | "杀毒安全",
22 | };
23 |
24 | /**
25 | * Leanback 横向 数据测试.
26 | */
27 | public static final List MOVIE_ITEMS = new ArrayList() {
28 | {
29 | add(new Movie(0, "天天2模拟器"));
30 | add(new Movie(0, "陌陌222"));
31 | add(new Movie(0, "爱奇艺222"));
32 | add(new Movie(0, "英雄2联盟2"));
33 | add(new Movie(0, "腾讯22视频"));
34 | add(new Movie(0, "QQ22音乐"));
35 | add(new Movie(0, "无敌22讯飞"));
36 | add(new Movie(0, "360浏览器"));
37 | add(new Movie(0, "美图秀秀"));
38 | add(new Movie(0, "YY语音"));
39 | add(new Movie(0, "迅雷"));
40 | add(new Movie(0, "腾讯视频"));
41 | add(new Movie(0, "酷狗阴影"));
42 | add(new Movie(0, "优酷"));
43 | add(new Movie(0, "篮球"));
44 | add(new Movie(0, "足球"));
45 | }
46 | };
47 |
48 | public static final List MOVIE_ITEMS2 = new ArrayList() {
49 | {
50 | add(new Movie(0, "天天模拟器AAA"));
51 | add(new Movie(0, "陌陌AAA"));
52 | add(new Movie(0, "爱奇艺222AAA"));
53 | add(new Movie(0, "英雄2联盟2AA"));
54 | add(new Movie(0, "腾讯视频AA"));
55 | add(new Movie(0, "酷狗阴影AA"));
56 | add(new Movie(0, "优酷AA"));
57 | add(new Movie(0, "篮球AA"));
58 | add(new Movie(0, "足球AAA1"));
59 | add(new Movie(0, "足球AAA15"));
60 | add(new Movie(0, "足球AAA16"));
61 | }
62 | };
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/Demo/app/src/main/java/com/open/demo/mode/Movie.java:
--------------------------------------------------------------------------------
1 | package com.open.demo.mode;
2 |
3 | /**
4 | * 用于Leanback 的数据测试.
5 | * Created by hailongqiu on 2016/8/25.
6 | */
7 | public class Movie {
8 | private int mRes;
9 | private String mTitle;
10 |
11 | public Movie(int res, String title) {
12 | this.mRes = res;
13 | this.mTitle = title;
14 | }
15 |
16 | public int getRes() {
17 | return this.mRes;
18 | }
19 |
20 | public String getTitle() {
21 | return this.mTitle;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/Demo/app/src/main/java/com/open/demo/mode/TestMoviceListPresenter.java:
--------------------------------------------------------------------------------
1 | package com.open.demo.mode;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.Drawable;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.util.Log;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.TextView;
11 |
12 | import com.open.androidtvwidget.leanback.mode.DefualtListPresenter;
13 | import com.open.androidtvwidget.leanback.recycle.RecyclerViewTV;
14 | import com.open.androidtvwidget.leanback.widget.ItemContainerView;
15 | import com.open.androidtvwidget.leanback.widget.ListContentView;
16 | import com.open.androidtvwidget.leanback.widget.OpenCardView;
17 | import com.open.demo.R;
18 |
19 | /**
20 | * Leanback 横向item demo.
21 | * 如果你想改变标题头的样式,那就写自己的吧.
22 | * Created by hailongqiu on 2016/8/25.
23 | */
24 | public class TestMoviceListPresenter extends DefualtListPresenter {
25 |
26 | boolean mIsSelect;
27 |
28 | /**
29 | * 你可以重写这里,传入AutoGridViewLayoutManger.
30 | */
31 | @Override
32 | public RecyclerView.LayoutManager getLayoutManger(Context context) {
33 | return super.getLayoutManger(context);
34 | }
35 |
36 | @Override
37 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
38 | View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.lb_h_item, parent, false);
39 | return new ViewHolder(itemView);
40 | }
41 |
42 | public void setSelect(boolean isSelect) {
43 | this.mIsSelect = isSelect;
44 | }
45 |
46 | @Override
47 | public void onBindViewHolder(final ViewHolder viewHolder, final int position) {
48 | Movie movie = ((Movie) getItem(position));
49 | OpenCardView openCardView = (OpenCardView) viewHolder.view;
50 | openCardView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
51 | @Override
52 | public void onFocusChange(View v, boolean hasFocus) {
53 | if (hasFocus) {
54 | v.animate().scaleX(1.2f).scaleY(1.2f).setDuration(300).start();
55 | } else {
56 | v.animate().scaleX(1.0f).scaleY(1.0f).setDuration(300).start();
57 | }
58 | }
59 | });
60 | openCardView.setBackgroundResource(R.drawable.mainview_cloudlist);
61 | Drawable d = viewHolder.view.getResources().getDrawable(R.drawable.ic_sp_block_focus);
62 | openCardView.setShadowDrawable(d);
63 | //
64 | TextView tv = (TextView) openCardView.findViewById(R.id.title_tv);
65 | tv.setText(movie.getTitle());
66 | //
67 | if (this.mIsSelect) {
68 | openCardView.setAlpha(0.5f);
69 | } else {
70 | openCardView.setAlpha(1.0f);
71 | }
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/Demo/app/src/main/java/com/open/demo/network/BaseLoader.java:
--------------------------------------------------------------------------------
1 | package com.open.demo.network;
2 |
3 | import android.content.Context;
4 | import android.content.Loader;
5 |
6 | /**
7 | * Created by hailongqiu on 2016/9/4.
8 | */
9 | public class BaseLoader extends Loader