有一段时间没有上来折腾这个专题了,一来项目的确紧张,二来自己一惯是很懒的。
今天想与大家分享的是一个QuickAction的东西,模样其实就是通讯录中点击头像后弹出的那个提供可操作按钮的窗口。
这个效果其实我们也用过,就是QuickContactBadge。显然,它很有意思,但是为什么只能由系统决定上面的按钮呢?
所以今天我们要做的事情就是做一个自己的QuickAction类。
第一步:收集资源
去Android的源代码网站 http://android.git.kernel.org/ 下载 Contacts 应用的源代码。在它的drawable目录里可以找到那些以quickcontacts_XXXXX的图片,就是我们需要用
来构造这个弹出窗口的图片资源。在layout目录里有quickcontact.xml则是我们需要的布局文件模板。当然,你也可以参考看看src/.../QuickContactsWindows.java文件。因为里
面就有今天我们要实现的内容,只是它太复杂了,已超出我们想要的功能。
第二步:设计布局
我们的布局文件quickaction.xml如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- >
- <FrameLayout
- android:id="@id/qa_header"
- android:background="@drawable/quickcontact_top_frame"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="10.0dip" />
- <ImageView
- android:id="@id/qa_arrow_up"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/quickcontact_arrow_up" />
-
- <HorizontalScrollView
- android:id="@id/qa_scroll"
- android:background="@drawable/quickcontact_slider_background"
- android:scrollbars="none"
- android:fadingEdgeLength="0.0dip"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/qa_header">
- <LinearLayout
- android:orientation="horizontal"
- android:id="@id/qa_tracks"
- android:paddingTop="4.0dip"
- android:paddingBottom="4.0dip"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/quickcontact_slider_grip_left" />
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/quickcontact_slider_grip_right" />
- </LinearLayout>
- </HorizontalScrollView>
-
- <FrameLayout
- android:id="@id/qa_footer"
- android:background="@drawable/quickcontact_bottom_frame"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_below="@id/qa_scroll" />
- <ImageView
- android:id="@id/qa_arrow_down"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="-1.0dip"
- android:src="@drawable/quickcontact_arrow_down"
- android:layout_below="@id/qa_footer" />
- </RelativeLayout>
里面很多东西都好理解,无非就是把图片堆砌一下罢了。重点说说放在中间的那个HorizontalScrollView里面的那个叫qa_tracks的LinearLayout。我们将来的所有按钮都是放在它
上面的,现在已经放了两个按钮(就是两边带点点的装饰按钮)。
第三步:现在开始写代码了,封装按钮的动作
- public class ActionItem {
- private Drawable icon;
- private View.OnClickListener listener;
-
- }
代码超简单,只需要两样东西:图标和事件监听器。
第四步:现在可以做QuickAction了
其实原理就是利用PopupWindow来显示quickaction布局文件,构造多个ActionItem实例放在qa_tracks里面就OK了。
具体实现如下:
- public class QuickAction {
- private static final String TAG="QuickAction";
- protected final View anchor;
-
- private View root;
- public final PopupWindow window;
- protected final WindowManager windowManager;
-
- private ArrayList<ActionItem> actionList;
-
- private final Context mContext;
- private final LayoutInflater inflater;
- private final ImageView mArrowDown;
- private final ImageView mArrowUp;
- private ViewGroup mTrack;
- private final Animation mTrackAnim;
- private Interpolator mAnimationInterpolator = new Interpolator(){
- @Override
- public float getInterpolation(float i) {
-
-
- final float inner = (i * 1.55f) - 1.1f;
- return 1.2f - inner * inner;
- }};
- public QuickAction(View v) {
- this.anchor = v;
-
- this.mContext = v.getContext();
- this.inflater = LayoutInflater.from(this.mContext);
-
- this.window = new PopupWindow(mContext);
- this.window.setTouchInterceptor(new View.OnTouchListener() {
-
- @Override
- public boolean onTouch(View view, MotionEvent event) {
-
- if (event.getAction() == MotionEvent.ACTION_OUTSIDE)
- dismiss();
- return false;
- }
- });
-
- windowManager = (WindowManager)mContext.getSystemService("window");
-
- this.actionList = new ArrayList<ActionItem>();
-
- this.root = (ViewGroup)this.inflater.inflate(R.layout.quickaction, null);
-
- this.mArrowDown = (ImageView)this.root.findViewById(R.id.qa_arrow_down);
- this.mArrowUp = (ImageView)this.root.findViewById(R.id.qa_arrow_up);
-
- this.window.setContentView(this.root);
-
-
- this.mTrackAnim = AnimationUtils.loadAnimation(this.mContext, R.anim.quickcontact);
- this.mTrackAnim.setInterpolator(mAnimationInterpolator);
-
- this.mTrack = (ViewGroup)this.root.findViewById(R.id.qa_tracks);
-
- }
- public void dismiss() {
- this.window.dismiss();
- }
-
- private void createActionList() {
- int i = 1;
- for(ActionItem ai : this.actionList){
- Drawable icon = ai.getIcon();
- View.OnClickListener listener=ai.getListener();
- View v = getActionItem(icon,listener);
- v.setFocusable(true);
- v.setClickable(true);
- this.mTrack.addView(v,i);
- i++;
- }
-
- }
- private View getActionItem(Drawable icon, View.OnClickListener listener) {
- LinearLayout view = (LinearLayout)this.inflater.inflate(R.layout.action_item, null);
- ImageView ic = (ImageView)view.findViewById(R.id.ai_icon);
-
- if (icon != null){
- ic.setImageDrawable(icon);
- if( listener!=null)
- view.setOnClickListener(listener);
-
- view.setVisibility(View.VISIBLE);
- }
- else
- view.setVisibility(View.GONE);
-
- return view;
- }
-
- public void addActionItem(ActionItem item) {
- this.actionList.add(item);
- }
- public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
- this.window.setOnDismissListener(listener);
- }
-
- protected void preShow() {
- if (this.root == null) throw new IllegalStateException("setContentView was not called with a view to display.");
- this.window.setBackgroundDrawable(new BitmapDrawable());
-
- this.window.setWidth(LayoutParams.FILL_PARENT);
- this.window.setHeight(LayoutParams.WRAP_CONTENT);
- this.window.setTouchable(true);
- this.window.setFocusable(true);
- this.window.setOutsideTouchable(true);
- this.window.setContentView(this.root);
-
-
- this.window.setAnimationStyle(R.style.QuickContactAboveAnimation);
-
- }
-
- private void showArrow(int resId, int margin) {
- ImageView v1=this.mArrowDown;
- ImageView v2=this.mArrowUp;
-
- if (resId == R.id.qa_arrow_up){
- v1 = this.mArrowUp;
- v2= this.mArrowDown;
- }
-
- int w = v1.getMeasuredWidth()/2;
- v1.setVisibility(View.VISIBLE);
- ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)v1.getLayoutParams();
- params.leftMargin=margin-w;
- v2.setVisibility(View.INVISIBLE);
- }
- public void show() {
- preShow();
-
- int[] loc = new int[2];
- this.anchor.getLocationOnScreen(loc);
- int i = loc[0];
- int j = loc[1];
-
- int w = i + this.anchor.getWidth();
- int h = j + this.anchor.getHeight();
-
- Rect localRect = new Rect(i, j, w, h);
- this.root.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
- this.root.measure(MeasureSpec.UNSPECIFIED,MeasureSpec.UNSPECIFIED);
-
- int ww = this.root.getMeasuredWidth();
- int hh = this.root.getMeasuredHeight();
-
- int dw = this.windowManager.getDefaultDisplay().getWidth();
-
- int xx = ( dw- ww) / 2;
- int yy = localRect.top - hh + 10;
-
- boolean isArrowDown = true;
- if (hh > (localRect.top - 50)) {
- yy = localRect.bottom - 10;
- isArrowDown = false;
- }
-
- {
- int rid=isArrowDown?R.id.qa_arrow_down:R.id.qa_arrow_up;
- showArrow(rid, localRect.centerX());
-
- createActionList();
-
- this.window.showAtLocation(this.anchor, Gravity.NO_GRAVITY, xx, yy);
-
-
- this.mTrack.startAnimation(this.mTrackAnim);
-
- }
- }
- }
不多解释了,注意事项参考代码中的注释即可。
那些漂亮的动画是必不可少的,而这又是GOOGLE已经提供了的,拿来用就是了。
最后的步骤:用它
在你要使用的地方(即原来放badge 位置上,修改成这样):
- <!--
- <QuickContactBadge
- android:id="@id/badge"
- style="@style/QCBTheme"
- android:background="#ffffff"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- />
- -->
- <ImageView
- android:id="@id/badge"
- style="@style/QCBTheme"
- android:background="#ffffff"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_alignParentLeft="true"
- android:layout_centerVertical="true"
- />
现在,在你的代码中手工构造并填写Action即可:
-
-
-
- ActionItem call=new ActionItem();
- call.setIcon(mContext.getResources().getDrawable(R.drawable.select_call));
- call.setOnClickListener(mToast);
-
-
-
-
-
- final ImageView photo=
- (ImageView)convertView.findViewById(R.id.badge);
-
-
-
- photo.setOnClickListener(new OnClickListener(){
- @Override
- public void onClick(View v) {
- action=new QuickAction(v);
-
-
- action.addActionItem(call);
- action.addActionItem(imsg);
- action.addActionItem(detail);
-
-
- action.show();
- }});