阅读481 返回首页    go 阿里云 go 技术社区[云栖]


创新源于模仿之五:做一个自己的QuickAction

 有一段时间没有上来折腾这个专题了,一来项目的确紧张,二来自己一惯是很懒的。
今天想与大家分享的是一个QuickAction的东西,模样其实就是通讯录中点击头像后弹出的那个提供可操作按钮的窗口。

 

 

这个效果其实我们也用过,就是QuickContactBadge。显然,它很有意思,但是为什么只能由系统决定上面的按钮呢?
所以今天我们要做的事情就是做一个自己的QuickAction类。


第一步:收集资源

去Android的源代码网站 https://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:andro
	android:layout_width="fill_parent" 
	android:layout_height="wrap_content"
>
    <FrameLayout
    	android:
    	android:background="@drawable/quickcontact_top_frame" 
    	android:layout_width="fill_parent" 
    	android:layout_height="wrap_content" 
    	android:layout_marginTop="10.0dip" />
    <ImageView
    	android:
    	android:layout_width="wrap_content" 
    	android:layout_height="wrap_content" 
    	android:src="@drawable/quickcontact_arrow_up" />
    	
    <HorizontalScrollView 
    	android: 
    	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: 
        	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: 
    	android:background="@drawable/quickcontact_bottom_frame" 
    	android:layout_width="fill_parent" 
    	android:layout_height="wrap_content" 
    	android:layout_below="@id/qa_scroll" />
    <ImageView 
    	android: 
    	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; //这里存放了很多的动作ActionItem
   
    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) {
            // TODO Auto-generated method stub
            //这个插值很重要,弹簧效果哦
            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) {
                // TODO Auto-generated method stub
                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);
       
        //这里的动画anim文件及style,参考Contacts里的相应文件
        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);
       
        //这里的动画anim文件及style,参考Contacts里的相应文件
        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);
            //showDropDown();
           
            this.mTrack.startAnimation(this.mTrackAnim);
         
        }
      }
}



不多解释了,注意事项参考代码中的注释即可。

那些漂亮的动画是必不可少的,而这又是GOOGLE已经提供了的,拿来用就是了。

 

最后的步骤:用它

 

在你要使用的地方(即原来放badge 位置上,修改成这样):

 

<!-- 
        <QuickContactBadge 
        	android: 
        	
        	android:background="#ffffff"
        	android:layout_width="fill_parent"
        	android:layout_height="fill_parent"
        	android:layout_alignParentLeft="true" 
        	android:layout_centerVertical="true" 
        	 />  
        -->
        <ImageView
         	android: 
        	
        	android:background="#ffffff"
        	android:layout_width="fill_parent"
        	android:layout_height="fill_parent"
        	android:layout_alignParentLeft="true" 
        	android:layout_centerVertical="true" 
        	 />


 

 

现在,在你的代码中手工构造并填写Action即可:

 

//省略代码
//......
//构造ActionItem,设置好图标及点击事件监听器
ActionItem call=new ActionItem();
		call.setIcon(mContext.getResources().getDrawable(R.drawable.select_call));
call.setOnClickListener(mToast);
//,,,,,,
//,,,,,,

//QuickContactBadge photo = (QuickContactBadge)convertView.findViewById(R.id.badge);
//找到锚点				
final ImageView photo=
(ImageView)convertView.findViewById(R.id.badge);
//省略代码
//,,,,,,
//点击头像时弹出QuickAction
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();
}});


 

最后更新:2017-04-02 06:51:59

  上一篇:go gcc编译报错:程序中有游离的‘\357’‘\273’‘\277’等 解决方法
  下一篇:go Android-非常棒的HTTP通讯总结