这节,四个议题:
①一个网页显示在webview控件中
②如何正常隐藏显示标题栏。
③如何用runnable来隐藏标题栏,这样子就更加的专业化。
④上节我们说道了QuickActionGrid,看他长得怎么样。
如何显示webview控件了,This is a question?这个除了上面的文章的支持外,主要是这个updateUI的方法。
/** * Update the UI: Url edit text, previous/next button state,... */ private void updateUI() { mUrlEditText.removeTextChangedListener(mUrlTextWatcher); mUrlEditText.setText(mCurrentWebView.getUrl()); mUrlEditText.addTextChangedListener(mUrlTextWatcher); mPreviousButton.setEnabled(mCurrentWebView.canGoBack()); mNextButton.setEnabled(mCurrentWebView.canGoForward()); if (mCurrentWebView.getUrl() != null) mRemoveTabButton.setEnabled((mViewFlipper.getChildCount() > 1 || !mCurrentWebView.getUrl().equals(Constants.URL_ABOUT_START))); else mRemoveTabButton.setEnabled(mViewFlipper.getChildCount() > 1); mProgressBar.setProgress(mCurrentWebView.getProgress()); updateGoButton(); updateTitle(); updateFavIcon(); }
这段代码是如此的熟悉,我们也来总结总结:
①我们需要更新URL文本框的数据,添加新的事件的监听。
②把前一步,后一步按钮设置是否禁用。
③把移去按钮,设置是否禁用。
④把进度条进度进行更新。
⑤更新去哪儿的按钮
⑥更新相应的标题
⑦更新相应的图标
这个webview视图进行显示了,相应视图也进行更新了。
如何正常显示标题栏,这个就是updateTitle方法做的事情,来瞧一瞧:
/** * Update the application title. */ private void updateTitle() { String value = mCurrentWebView.getTitle(); if ((value != null) && (value.length() > 0)) { this.setTitle(String.format(getResources().getString(R.string.ApplicationNameUrl), value)); } else { clearTitle(); } }
这是一个更新标题的方法,我们可以得出来相应总结,
①我们可以获取当前webview的标题,如果是标题不为空的话,我们就设置相应的标题。否则就清空标题.
正常的隐藏标题栏,极大提高了用户体验,这是一个runnable接口功劳,那具体怎么做了:
1 /** 2 * Start a runnable to hide the tool bars after a user-defined delay. 3 */ 4 private void startToolbarsHideRunnable() { 5 6 if (mHideToolbarsRunnable != null) { 7 mHideToolbarsRunnable.setDisabled(); 8 } 9 10 int delay = Integer.parseInt(Controller.getInstance().getPreferences().getString(Constants.PREFERENCES_GENERAL_BARS_DURATION, "3000")); 11 if (delay <= 0) { 12 delay = 3000; 13 } 14 15 mHideToolbarsRunnable = new HideToolbarsRunnable(this, delay); 16 new Thread(mHideToolbarsRunnable).start(); 17 } 18 19 /** 20 * Hide the tool bars. 21 */ 22 public void hideToolbars() { 23 if (mUrlBarVisible) { 24 if ((!mUrlEditText.hasFocus()) && 25 (!mToolsActionGridVisible)) { 26 27 if (!mCurrentWebView.isLoading()) { 28 setToolbarsVisibility(false); 29 } 30 } 31 } 32 mHideToolbarsRunnable = null; 33 }
我这里能够得到这样的提示了:
①用到sharedpreference看用户设置时间,如果没有设置时间的话,默认是3秒就开启一条线程将其标题栏隐藏了。为什么会用到多线程了,这样不会更新主界面造成卡顿的现象。
②如果toolbar是隐藏的,就将其隐藏。
QuickActionGrid是一个自定义控件,为什么用自定义控件了,
①android自带的控件太多bug。
②自定义控件也非常的灵活。
源代码如下:
public class QuickActionGrid extends QuickActionWidget { // grid 控件 private GridView mGridView; /** * grid 构造函数 数据的初始化 * @param context 上下文对象 */ public QuickActionGrid(Context context) { super(context); setContentView(R.layout.gd_quick_action_grid); final View v = getContentView(); mGridView = (GridView) v.findViewById(R.id.gdi_grid); } /** * 弹出相应的action的方法 */ @Override protected void populateQuickActions(final List<QuickAction> quickActions) { mGridView.setAdapter(new BaseAdapter() { public View getView(int position, View view, ViewGroup parent) { TextView textView = (TextView) view; if (view == null) { final LayoutInflater inflater = LayoutInflater.from(getContext()); textView = (TextView) inflater.inflate(R.layout.gd_quick_action_grid_item, mGridView, false); } QuickAction quickAction = quickActions.get(position); textView.setText(quickAction.mTitle); textView.setCompoundDrawablesWithIntrinsicBounds(null, quickAction.mDrawable, null, null); return textView; } public long getItemId(int position) { return position; } public Object getItem(int position) { return null; } public int getCount() { return quickActions.size(); } }); mGridView.setOnItemClickListener(mInternalItemClickListener); } /** * 尺寸改变的事件 */ @Override protected void onMeasureAndLayout(Rect anchorRect, View contentView) { contentView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); contentView.measure(MeasureSpec.makeMeasureSpec(getScreenWidth(), MeasureSpec.EXACTLY), LayoutParams.WRAP_CONTENT); int rootHeight = contentView.getMeasuredHeight(); int offsetY = getArrowOffsetY(); int dyTop = anchorRect.top; int dyBottom = getScreenHeight() - anchorRect.bottom; boolean onTop = (dyTop > dyBottom); int popupY = (onTop) ? anchorRect.top - rootHeight + offsetY : anchorRect.bottom - offsetY; setWidgetSpecs(popupY, onTop); } /** * 每项点击的事件 */ private OnItemClickListener mInternalItemClickListener = new OnItemClickListener() { public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { getOnQuickActionClickListener().onQuickActionClicked(QuickActionGrid.this, position); if (getDismissOnClick()) { dismiss(); } } }; }
这个quickGrid控件是继承与quickWidget控件,这也是一个自定义控件。对于他这个方法,我们集中于populateQuickActions方法和onMeasureAndLayout方法。
①populateQuickActions方法其实就是一个填充相应数据的方法,就是把相应的数据通过baseAdapter填充与gridview控件,gridview控件用于显示相应数据项。
②mInternalItemClickListener方法了,就是为每一个item赋予点击事件,如果这个点击动作已经执行以后,就相应弹出的popwindow就进行了隐藏。
quickwidget控件在这个项目用的很多,这是许多控件的基类,怎么写的。
1 private static final int MEASURE_AND_LAYOUT_DONE = 1 << 1; 2 3 private final int[] mLocation = new int[2]; 4 private final Rect mRect = new Rect(); 5 6 private int mPrivateFlags; 7 8 private Context mContext; 9 10 private boolean mDismissOnClick; 11 private int mArrowOffsetY; 12 13 private int mPopupY; 14 private boolean mIsOnTop; 15 16 private int mScreenHeight; 17 private int mScreenWidth; 18 private boolean mIsDirty; 19 20 private OnQuickActionClickListener mOnQuickActionClickListener; 21 private ArrayList<QuickAction> mQuickActions = new ArrayList<QuickAction>(); 22 23 /** 24 * Interface that may be used to listen to clicks on quick actions. 25 * 26 * @author Benjamin Fellous 27 * @author Cyril Mottier 28 */ 29 public static interface OnQuickActionClickListener { 30 /** 31 * Clients may implement this method to be notified of a click on a 32 * particular quick action. 33 * 34 * @param position Position of the quick action that have been clicked. 35 */ 36 void onQuickActionClicked(QuickActionWidget widget, int position); 37 } 38 39 /** 40 * Creates a new QuickActionWidget for the given context. 41 * 42 * @param context The context in which the QuickActionWidget is running in 43 */ 44 public QuickActionWidget(Context context) { 45 super(context); 46 47 mContext = context; 48 49 initializeDefault(); 50 51 setFocusable(true); 52 setTouchable(true); 53 setOutsideTouchable(true); 54 setWidth(WindowManager.LayoutParams.WRAP_CONTENT); 55 setHeight(WindowManager.LayoutParams.WRAP_CONTENT); 56 57 final WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 58 mScreenWidth = windowManager.getDefaultDisplay().getWidth(); 59 mScreenHeight = windowManager.getDefaultDisplay().getHeight(); 60 } 61 62 /** 63 * Equivalent to {@link PopupWindow#setContentView(View)} but with a layout 64 * identifier. 65 * 66 * @param layoutId The layout identifier of the view to use. 67 */ 68 public void setContentView(int layoutId) { 69 setContentView(LayoutInflater.from(mContext).inflate(layoutId, null)); 70 } 71 72 private void initializeDefault() { 73 mDismissOnClick = true; 74 mArrowOffsetY = mContext.getResources().getDimensionPixelSize(R.dimen.gd_arrow_offset); 75 } 76 77 /** 78 * Returns the arrow offset for the Y axis. 79 * 80 * @see {@link #setArrowOffsetY(int)} 81 * @return The arrow offset. 82 */ 83 public int getArrowOffsetY() { 84 return mArrowOffsetY; 85 } 86 87 /** 88 * Sets the arrow offset to a new value. Setting an arrow offset may be 89 * particular useful to warn which view the QuickActionWidget is related to. 90 * By setting a positive offset, the arrow will overlap the view given by 91 * {@link #show(View)}. The default value is 5dp. 92 * 93 * @param offsetY The offset for the Y axis 94 */ 95 public void setArrowOffsetY(int offsetY) { 96 mArrowOffsetY = offsetY; 97 } 98 99 /** 100 * Returns the width of the screen. 101 * 102 * @return The width of the screen 103 */ 104 protected int getScreenWidth() { 105 return mScreenWidth; 106 } 107 108 /** 109 * Returns the height of the screen. 110 * 111 * @return The height of the screen 112 */ 113 protected int getScreenHeight() { 114 return mScreenHeight; 115 } 116 117 /** 118 * By default, a {@link QuickActionWidget} is dismissed once the user 119 * clicked on a {@link QuickAction}. This behavior can be changed using this 120 * method. 121 * 122 * @param dismissOnClick True if you want the {@link QuickActionWidget} to 123 * be dismissed on click else false. 124 */ 125 public void setDismissOnClick(boolean dismissOnClick) { 126 mDismissOnClick = dismissOnClick; 127 } 128 129 public boolean getDismissOnClick() { 130 return mDismissOnClick; 131 } 132 133 /** 134 * @param listener 135 */ 136 public void setOnQuickActionClickListener(OnQuickActionClickListener listener) { 137 mOnQuickActionClickListener = listener; 138 } 139 140 /** 141 * Add a new QuickAction to this {@link QuickActionWidget}. Adding a new 142 * {@link QuickAction} while the {@link QuickActionWidget} is currently 143 * being shown does nothing. The new {@link QuickAction} will be displayed 144 * on the next call to {@link #show(View)}. 145 * 146 * @param action The new {@link QuickAction} to add 147 */ 148 public void addQuickAction(QuickAction action) { 149 if (action != null) { 150 mQuickActions.add(action); 151 mIsDirty = true; 152 } 153 } 154 155 /** 156 * Removes all {@link QuickAction} from this {@link QuickActionWidget}. 157 */ 158 public void clearAllQuickActions() { 159 if (!mQuickActions.isEmpty()) { 160 mQuickActions.clear(); 161 mIsDirty = true; 162 } 163 } 164 165 /** 166 * Call that method to display the {@link QuickActionWidget} anchored to the 167 * given view. 168 * 169 * @param anchor The view the {@link QuickActionWidget} will be anchored to. 170 */ 171 public void show(View anchor) { 172 173 final View contentView = getContentView(); 174 175 if (contentView == null) { 176 throw new IllegalStateException("You need to set the content view using the setContentView method"); 177 } 178 179 // Replaces the background of the popup with a cleared background 180 setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); 181 182 final int[] loc = mLocation; 183 anchor.getLocationOnScreen(loc); 184 mRect.set(loc[0], loc[1], loc[0] + anchor.getWidth(), loc[1] + anchor.getHeight()); 185 186 if (mIsDirty) { 187 clearQuickActions(); 188 populateQuickActions(mQuickActions); 189 } 190 191 onMeasureAndLayout(mRect, contentView); 192 193 if ((mPrivateFlags & MEASURE_AND_LAYOUT_DONE) != MEASURE_AND_LAYOUT_DONE) { 194 throw new IllegalStateException("onMeasureAndLayout() did not set the widget specification by calling" 195 + " setWidgetSpecs()"); 196 } 197 198 showArrow(); 199 prepareAnimationStyle(); 200 showAtLocation(anchor, Gravity.NO_GRAVITY, 0, mPopupY); 201 } 202 203 protected void clearQuickActions() { 204 if (!mQuickActions.isEmpty()) { 205 onClearQuickActions(); 206 } 207 } 208 209 protected void onClearQuickActions() { 210 } 211 212 protected abstract void populateQuickActions(List<QuickAction> quickActions); 213 214 protected abstract void onMeasureAndLayout(Rect anchorRect, View contentView); 215 216 protected void setWidgetSpecs(int popupY, boolean isOnTop) { 217 mPopupY = popupY; 218 mIsOnTop = isOnTop; 219 220 mPrivateFlags |= MEASURE_AND_LAYOUT_DONE; 221 } 222 223 private void showArrow() { 224 225 final View contentView = getContentView(); 226 final int arrowId = mIsOnTop ? R.id.gdi_arrow_down : R.id.gdi_arrow_up; 227 final View arrow = contentView.findViewById(arrowId); 228 final View arrowUp = contentView.findViewById(R.id.gdi_arrow_up); 229 final View arrowDown = contentView.findViewById(R.id.gdi_arrow_down); 230 231 if (arrowId == R.id.gdi_arrow_up) { 232 arrowUp.setVisibility(View.VISIBLE); 233 arrowDown.setVisibility(View.INVISIBLE); 234 } else if (arrowId == R.id.gdi_arrow_down) { 235 arrowUp.setVisibility(View.INVISIBLE); 236 arrowDown.setVisibility(View.VISIBLE); 237 } 238 239 ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams) arrow.getLayoutParams(); 240 param.leftMargin = mRect.centerX() - (arrow.getMeasuredWidth()) / 2; 241 } 242 243 private void prepareAnimationStyle() { 244 245 final int screenWidth = mScreenWidth; 246 final boolean onTop = mIsOnTop; 247 final int arrowPointX = mRect.centerX(); 248 249 if (arrowPointX <= screenWidth / 4) { 250 setAnimationStyle(onTop ? R.style.GreenDroid_Animation_PopUp_Left 251 : R.style.GreenDroid_Animation_PopDown_Left); 252 } else if (arrowPointX >= 3 * screenWidth / 4) { 253 setAnimationStyle(onTop ? R.style.GreenDroid_Animation_PopUp_Right 254 : R.style.GreenDroid_Animation_PopDown_Right); 255 } else { 256 setAnimationStyle(onTop ? R.style.GreenDroid_Animation_PopUp_Center 257 : R.style.GreenDroid_Animation_PopDown_Center); 258 } 259 } 260 261 protected Context getContext() { 262 return mContext; 263 } 264 265 protected OnQuickActionClickListener getOnQuickActionClickListener() { 266 return mOnQuickActionClickListener; 267 }
首先这个控件本质是Popwindow,对于这个控件我们要探讨的有这么几点:
①show这个方法中了,主要是根据相应的锚基点来弹出来了,并且在指定的位置弹出相应的窗口。
②在showarrow这个方法,我们需要根据是否向上还是向下显示相应的箭头,给用户一个很好的提示。
③在动画的操作方法中,我们要根据其坐标是否小于全频宽度的四分之一位置,从左边的位置弹出来,其坐标从全频宽度四分之三的位置,从右侧位置弹出来了。
有了这篇文章介绍,主界面应该了解了把?下节介绍收藏和历史界面。