react-native-navigation的迁移库

RnnToolBar.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. package com.reactnativenavigation.views;
  2. import android.app.Activity;
  3. import android.content.Context;
  4. import android.graphics.Color;
  5. import android.graphics.drawable.Drawable;
  6. import android.os.AsyncTask;
  7. import android.support.annotation.ColorInt;
  8. import android.support.annotation.NonNull;
  9. import android.support.annotation.UiThread;
  10. import android.support.v4.widget.DrawerLayout;
  11. import android.support.v7.app.ActionBar;
  12. import android.support.v7.app.ActionBarDrawerToggle;
  13. import android.support.v7.app.AppCompatActivity;
  14. import android.support.v7.graphics.drawable.DrawerArrowDrawable;
  15. import android.support.v7.widget.Toolbar;
  16. import android.util.AttributeSet;
  17. import android.view.Gravity;
  18. import android.view.Menu;
  19. import android.view.MenuItem;
  20. import android.view.View;
  21. import android.view.ViewTreeObserver;
  22. import android.widget.TextView;
  23. import com.reactnativenavigation.R;
  24. import com.reactnativenavigation.activities.BaseReactActivity;
  25. import com.reactnativenavigation.core.objects.Button;
  26. import com.reactnativenavigation.core.objects.Screen;
  27. import com.reactnativenavigation.utils.ContextProvider;
  28. import com.reactnativenavigation.react.ImageLoader;
  29. import com.reactnativenavigation.utils.ImageUtils;
  30. import java.lang.ref.WeakReference;
  31. import java.util.ArrayList;
  32. import java.util.HashMap;
  33. import java.util.List;
  34. import java.util.Map;
  35. /**
  36. * Created by guyc on 09/04/16.
  37. */
  38. public class RnnToolBar extends Toolbar {
  39. private List<Screen> mScreens;
  40. private AsyncTask mDrawerIconTask;
  41. private AsyncTask mSetupToolbarTask;
  42. private Drawable mBackground;
  43. private Drawable mDrawerIcon;
  44. private DrawerLayout mDrawerLayout;
  45. private ActionBarDrawerToggle mDrawerToggle;
  46. private ArrayList<View> mMenuItems;
  47. public RnnToolBar(Context context) {
  48. super(context);
  49. init();
  50. }
  51. private void init() {
  52. mMenuItems = new ArrayList<>();
  53. mBackground = getBackground();
  54. }
  55. public void setScreens(List<Screen> screens) {
  56. mScreens = screens;
  57. }
  58. public void handleOnCreateOptionsMenuAsync() {
  59. // if (mScreens != null) {
  60. // setupToolbarButtonsAsync(null, mScreens.get(0));
  61. // }
  62. }
  63. public ActionBarDrawerToggle setupDrawer(DrawerLayout drawerLayout, Screen drawerScreen, Screen screen) {
  64. if (drawerLayout == null || drawerScreen == null) {
  65. return null;
  66. }
  67. mDrawerLayout = drawerLayout;
  68. mDrawerToggle = new ActionBarDrawerToggle(
  69. ContextProvider.getActivityContext(),
  70. mDrawerLayout,
  71. this,
  72. R.string.drawer_open,
  73. R.string.drawer_close
  74. );
  75. mDrawerLayout.setDrawerListener(mDrawerToggle);
  76. setupDrawerIconAsync(drawerScreen.icon, screen);
  77. return mDrawerToggle;
  78. }
  79. public void setDrawerIcon(Drawable icon) {
  80. mDrawerIcon = icon;
  81. }
  82. public void showDrawer(boolean animated) {
  83. if (mDrawerLayout == null) {
  84. return;
  85. }
  86. mDrawerLayout.openDrawer(Gravity.LEFT);
  87. }
  88. public void hideDrawer(boolean animated) {
  89. if (mDrawerLayout == null) {
  90. return;
  91. }
  92. mDrawerLayout.closeDrawer(Gravity.LEFT);
  93. }
  94. public void toggleDrawer(boolean animated) {
  95. if (mDrawerLayout == null) {
  96. return;
  97. }
  98. boolean visible = mDrawerLayout.isDrawerOpen(Gravity.LEFT);
  99. if (visible) {
  100. hideDrawer(animated);
  101. } else {
  102. showDrawer(animated);
  103. }
  104. }
  105. public void setupDrawerIconAsync(String drawerIconSource, Screen screen) {
  106. if (mDrawerIconTask == null) {
  107. mDrawerIconTask = new SetupDrawerIconTask(this, drawerIconSource, screen).execute();
  108. }
  109. }
  110. public void setupToolbarButtonsAsync(Screen newScreen) {
  111. if (newScreen != null) {
  112. this.setupToolbarButtonsAsync(null, newScreen);
  113. }
  114. }
  115. public void setupToolbarButtonsAsync(Screen oldScreen, Screen newScreen) {
  116. if (mSetupToolbarTask == null) {
  117. mSetupToolbarTask = new SetupToolbarButtonsTask(this, oldScreen, newScreen).execute();
  118. }
  119. }
  120. public void showToolbar(boolean animated) {
  121. ActionBar actionBar = ((AppCompatActivity) getContext()).getSupportActionBar();
  122. if (actionBar != null) {
  123. actionBar.setShowHideAnimationEnabled(animated);
  124. // We hide the ToolBar's parent (AppBarLayout) since this animates the shadow added by AppBar as well
  125. ((View) getParent()).setVisibility(VISIBLE);
  126. }
  127. }
  128. public void hideToolbar(boolean animated) {
  129. ActionBar actionBar = ((AppCompatActivity) getContext()).getSupportActionBar();
  130. if (actionBar != null) {
  131. actionBar.setShowHideAnimationEnabled(animated);
  132. // We hide the ToolBar's parent (AppBarLayout) since this animates the shadow added by AppBar as well
  133. ((View) getParent()).setVisibility(GONE);
  134. }
  135. }
  136. private void showToolbar() {
  137. showToolbar(false);
  138. }
  139. private void hideToolbar() {
  140. hideToolbar(false);
  141. }
  142. public void setNavUpButton() {
  143. setNavUpButton(null);
  144. }
  145. @SuppressWarnings({"ConstantConditions"})
  146. public void setNavUpButton(Screen screen) {
  147. BaseReactActivity context = ContextProvider.getActivityContext();
  148. if (context == null) {
  149. return;
  150. }
  151. ActionBar actionBar = context.getSupportActionBar();
  152. if (actionBar == null) {
  153. return;
  154. }
  155. boolean isBack = screen != null;
  156. boolean hasDrawer = mDrawerToggle != null;
  157. Drawable navIcon = null;
  158. DrawerArrowDrawable navArrow = null;
  159. if (hasDrawer && mDrawerIcon == null) {
  160. navArrow = (DrawerArrowDrawable) this.getNavigationIcon();
  161. } else {
  162. if (isBack && !screen.backButtonHidden) {
  163. navArrow = new DrawerArrowDrawable(context);
  164. } else if (hasDrawer) {
  165. navIcon = mDrawerIcon;
  166. }
  167. }
  168. if (navArrow != null) {
  169. navArrow.setProgress(isBack ? 1.0f : 0.0f);
  170. if (screen != null && screen.navBarButtonColor != null) {
  171. navArrow.setColor(screen.navBarButtonColor);
  172. } else {
  173. navArrow.setColor(Color.BLACK);
  174. }
  175. navIcon = navArrow;
  176. }
  177. actionBar.setHomeAsUpIndicator(navIcon);
  178. actionBar.setDisplayHomeAsUpEnabled(navIcon != null);
  179. }
  180. /**
  181. * Update the ToolBar from screen. This function sets any properties that are defined
  182. * in the screen.
  183. * @param screen The currently displayed screen
  184. */
  185. @UiThread
  186. public void update(@NonNull Screen screen) {
  187. ((AppCompatActivity) getContext()).setSupportActionBar(this);
  188. setTitle(screen.title);
  189. setStyle(screen);
  190. }
  191. public void updateAndSetButtons(Screen screen) {
  192. update(screen);
  193. setupToolbarButtonsAsync(screen);
  194. }
  195. private static class SetupDrawerIconTask extends AsyncTask<Void, Void, Drawable> {
  196. private final WeakReference<RnnToolBar> mToolbarWR;
  197. private final String mDrawerIconSource;
  198. private final Integer mTintColor;
  199. public SetupDrawerIconTask(RnnToolBar toolBar, String drawerIconSource, Screen screen) {
  200. mToolbarWR = new WeakReference<>(toolBar);
  201. mDrawerIconSource = drawerIconSource;
  202. mTintColor = screen.navBarButtonColor;
  203. }
  204. @Override
  205. protected Drawable doInBackground(Void... params) {
  206. Context context = ContextProvider.getActivityContext();
  207. if (context == null || mDrawerIconSource == null) {
  208. return null;
  209. }
  210. return ImageLoader.loadImage(mDrawerIconSource);
  211. }
  212. @Override
  213. protected void onPostExecute(Drawable drawerIcon) {
  214. RnnToolBar toolBar = mToolbarWR.get();
  215. if (drawerIcon != null) {
  216. if (mTintColor != null) {
  217. ImageUtils.tint(drawerIcon, mTintColor);
  218. }
  219. toolBar.setDrawerIcon(drawerIcon);
  220. }
  221. toolBar.setNavUpButton();
  222. mToolbarWR.clear();
  223. }
  224. }
  225. private static class SetupToolbarButtonsTask extends AsyncTask<Void, Void, Map<String, Drawable>> {
  226. private final List<Button> mOldButtons;
  227. private final List<Button> mNewButtons;
  228. private final WeakReference<RnnToolBar> mToolbarWR;
  229. @ColorInt private final Integer mTintColor;
  230. private final int mIconDimensions;
  231. public SetupToolbarButtonsTask(RnnToolBar toolBar, Screen oldScreen, Screen newScreen) {
  232. mToolbarWR = new WeakReference<>(toolBar);
  233. mOldButtons = oldScreen == null ? null : oldScreen.getButtons();
  234. mNewButtons = newScreen.getButtons();
  235. mTintColor = newScreen.navBarButtonColor;
  236. mIconDimensions = (int) ImageUtils.convertDpToPixel(48, toolBar.getContext());
  237. }
  238. @Override
  239. protected Map<String, Drawable> doInBackground(Void... params) {
  240. Context context = ContextProvider.getActivityContext();
  241. if (context == null) {
  242. return null;
  243. }
  244. Map<String, Drawable> icons = new HashMap<>();
  245. for (Button button : mNewButtons) {
  246. if (button.hasIcon()) {
  247. icons.put(button.id, button.getIcon(context, mIconDimensions));
  248. }
  249. }
  250. return icons;
  251. }
  252. @Override
  253. protected void onPostExecute(Map<String, Drawable> icons) {
  254. final Context context = ContextProvider.getActivityContext();
  255. if (context == null) {
  256. return;
  257. }
  258. Menu menu = ((BaseReactActivity) context).getMenu();
  259. if (menu == null) {
  260. RnnToolBar toolBar = mToolbarWR.get();
  261. if (toolBar != null) {
  262. toolBar.mSetupToolbarTask = null;
  263. }
  264. mToolbarWR.clear();
  265. return;
  266. }
  267. // Remove prev screen buttons
  268. if(mOldButtons == null) {
  269. menu.clear();
  270. } else {
  271. for (Button btn : mOldButtons) {
  272. menu.removeItem(btn.getItemId());
  273. }
  274. }
  275. // Add new screen buttons
  276. final List<String> textButtons = new ArrayList<>();
  277. final int size = mNewButtons.size();
  278. for (int i = 0; i < size; i++) {
  279. Button button = mNewButtons.get(i);
  280. MenuItem item = menu.add(Menu.NONE, button.getItemId(), size - i - 1, button.title);
  281. item.setShowAsAction(getMenuItemShowAction(button.showAsAction));
  282. // Set button icon
  283. if (button.hasIcon()) {
  284. Drawable icon = icons.get(button.id);
  285. if (mTintColor != null) {
  286. ImageUtils.tint(icon, mTintColor);
  287. }
  288. item.setIcon(icon);
  289. } else {
  290. textButtons.add(button.title);
  291. }
  292. // Disable button if needed
  293. if (button.disabled) {
  294. item.setEnabled(false);
  295. }
  296. }
  297. final RnnToolBar toolBar = mToolbarWR.get();
  298. if (toolBar != null) {
  299. // Tint overflow icon which appears when there's not enough space in Toolbar for icons
  300. if (mTintColor != null) {
  301. ImageUtils.tint(toolBar.getOverflowIcon(), mTintColor);
  302. }
  303. // Tint text buttons
  304. if (textButtons.size() > 0 && mTintColor != null) {
  305. final View decorView = ((Activity) context).getWindow().getDecorView();
  306. decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
  307. @Override
  308. public void onGlobalLayout() {
  309. decorView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
  310. // Find TextViews
  311. for (String text : textButtons) {
  312. decorView.findViewsWithText(toolBar.mMenuItems, text, View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
  313. }
  314. // Set text color
  315. for (View button : toolBar.mMenuItems) {
  316. ((TextView) button).setTextColor(mTintColor);
  317. }
  318. toolBar.mMenuItems.clear();
  319. }
  320. });
  321. }
  322. toolBar.mSetupToolbarTask = null;
  323. mToolbarWR.clear();
  324. }
  325. }
  326. private int getMenuItemShowAction(String action) {
  327. switch (action) {
  328. case "never":
  329. return MenuItem.SHOW_AS_ACTION_NEVER;
  330. case "always":
  331. return MenuItem.SHOW_AS_ACTION_ALWAYS;
  332. case "withText":
  333. return MenuItem.SHOW_AS_ACTION_WITH_TEXT;
  334. default:
  335. return MenuItem.SHOW_AS_ACTION_IF_ROOM;
  336. }
  337. }
  338. }
  339. }