这节,四个议题:
①一个网页显示在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这个方法,我们需要根据是否向上还是向下显示相应的箭头,给用户一个很好的提示。
③在动画的操作方法中,我们要根据其坐标是否小于全频宽度的四分之一位置,从左边的位置弹出来,其坐标从全频宽度四分之三的位置,从右侧位置弹出来了。
有了这篇文章介绍,主界面应该了解了把?下节介绍收藏和历史界面。