android UI进阶之弹窗的使用(2)--实现通讯录的弹窗效果

来源:互联网 发布:js工厂方法 编辑:程序博客网 时间:2024/05/01 11:37
来源:http://www.apkbus.com/android-20080-1-2.html
相信大家都体验过android通讯录中的弹窗效果。如图所示:

111.jpg

android中提供了QuickContactBadge来实现这一效果。这里简单演示下。
首先创建布局文件:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3.               android:orientation="vertical" 
  4.               android:layout_width="fill_parent" 
  5.               android:layout_height="fill_parent" 
  6.         > 
  7.     <QuickContactBadge 
  8.             android:id="@+id/badge" 
  9.             android:layout_width="wrap_content" 
  10.             android:layout_height="wrap_content" 
  11.             android:src="@drawable/icon"> 
  12.     </QuickContactBadge> 
  13. </LinearLayout>
复制代码
很简单,在布局中添加一个QuickContactBadge组件即可。
在Activity中配置:
  1. public class QuickcontactActivity extends Activity {

  2.     /** Called when the activity is first created. */
  3.     @Override
  4.     public void onCreate(Bundle savedInstanceState) {
  5.         super.onCreate(savedInstanceState);
  6.         setContentView(R.layout.main);

  7.         QuickContactBadge smallBadge = (QuickContactBadge) findViewById(R.id.badge);
  8.         // 从email关联一个contact
  9.         smallBadge.assignContactFromEmail("notice520@gmail.com", true);
  10.         // 设置窗口模式
  11.         smallBadge.setMode(ContactsContract.QuickContact.MODE_SMALL);
  12.     }
  13. }
复制代码
注意加入读通讯录的权限

<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>  
实现效果如图:
222.jpg 

但是这个组件局限性很大,弹出窗口中只能是一些contact操作。但是仔细一想,这样的操作并不难,不就是一个带动画的弹窗么。下面就来我们自己实现一个。
实现一个带动画的弹窗并不难,在我的之前一篇博客中有讲过弹窗PopupWindow的使用,不清楚弹窗的朋友可以去看下。在这里实现的难点主要有这些:
1.判断基准view在屏幕中的位置,从而确定弹窗弹出的位置以及动画。这是非常重要的一点,或许基准在屏幕上方,那么就要向下弹出。
2.动态的添加弹窗中的按钮,并实现点击
3.箭头位置的控制。箭头应该保持在基准的下方。
4.动画的匹配。里面有两种动画。一种是PopupWindow弹出动画,我们通过设置弹窗的style来实现(style的用法可以参考我之前的博客)。另一种是弹窗中间的布局的动画。
  了解了难点以后,写起来就方便了。
首先实现弹窗的布局:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:layout_width="wrap_content"
  4.     android:layout_height="wrap_content">
  5.         
  6.      <FrameLayout
  7.           android:layout_marginTop="10dip"
  8.         android:id="@+id/header2"
  9.         android:layout_width="fill_parent"
  10.         android:layout_height="wrap_content"
  11.         android:background="@drawable/quickcontact_top_frame"/>
  12.         
  13.       <ImageView
  14.         android:id="@+id/arrow_up"
  15.         android:layout_width="wrap_content"
  16.         android:layout_height="wrap_content"    
  17.         android:src="@drawable/quickcontact_arrow_up" />
  18.        
  19.     <HorizontalScrollView
  20.         android:id="@+id/scroll"
  21.         android:layout_width="fill_parent"
  22.         android:layout_height="wrap_content"
  23.         android:fadingEdgeLength="0dip"
  24.         android:layout_below="@id/header2"
  25.         android:background="@drawable/quickcontact_slider_background"
  26.         android:scrollbars="none">

  27.         <LinearLayout
  28.             android:id="@+id/tracks"
  29.             android:layout_width="wrap_content"
  30.             android:layout_height="wrap_content"
  31.             android:paddingTop="4dip"
  32.             android:paddingBottom="4dip" 
  33.             android:orientation="horizontal">
  34.         
  35.             <ImageView
  36.                 android:layout_width="wrap_content"
  37.                 android:layout_height="wrap_content"
  38.                 android:src="@drawable/quickcontact_slider_grip_left" />

  39.             <ImageView
  40.                 android:layout_width="wrap_content"
  41.                 android:layout_height="wrap_content"
  42.                 android:src="@drawable/quickcontact_slider_grip_right" />
  43.                 
  44.         </LinearLayout>
  45.             
  46.     </HorizontalScrollView>

  47.     <FrameLayout
  48.         android:id="@+id/footer"
  49.         android:layout_width="fill_parent"
  50.         android:layout_height="wrap_content"
  51.         android:layout_below="@id/scroll"
  52.         android:background="@drawable/quickcontact_bottom_frame" />

  53.     <ImageView
  54.         android:id="@+id/arrow_down"
  55.         android:layout_width="wrap_content"
  56.         android:layout_height="wrap_content"
  57.         android:layout_marginTop="-1dip"
  58.         android:layout_below="@id/footer"
  59.         android:src="@drawable/quickcontact_arrow_down" />

  60. </RelativeLayout>
复制代码
窗体内部使用一个HorizontalScrollView可以实现一个滑动效果。我们可以动态的在这个布局中添加按钮,我们称作Actionitem。
  写一个ActionItem类,使得我们可以用一个ArrayList做容器,动态的添加这些actionitem。这些都是服务于第二个难点。
  1. package com.notice.quickaction;

  2. import android.graphics.drawable.Drawable;
  3. import android.view.View.OnClickListener;

  4. /**
  5. * Action item, 每个item里面都有一个ImageView和一个TextView
  6. */
  7. public class ActionItem {

  8.     private Drawable        icon;
  9.     private String          title;
  10.     private OnClickListener listener;

  11.     /**
  12.      * 构造器
  13.      */
  14.     public ActionItem() {
  15.     }

  16.     /**
  17.      * 带Drawable参数的构造器
  18.      */
  19.     public ActionItem(Drawable icon) {
  20.         this.icon = icon;
  21.     }

  22.     /**
  23.      * 设置标题
  24.      */
  25.     public void setTitle(String title) {
  26.         this.title = title;
  27.     }

  28.     /**
  29.      * 获得标题
  30.      * 
  31.      * @return action title
  32.      */
  33.     public String getTitle() {
  34.         return this.title;
  35.     }

  36.     /**
  37.      * 设置图标
  38.      */
  39.     public void setIcon(Drawable icon) {
  40.         this.icon = icon;
  41.     }

  42.     /**
  43.      * 获得图标
  44.      */
  45.     public Drawable getIcon() {
  46.         return this.icon;
  47.     }

  48.     /**
  49.      * 绑定监听器
  50.      */
  51.     public void setOnClickListener(OnClickListener listener) {
  52.         this.listener = listener;
  53.     }

  54.     /**
  55.      * 获得监听器
  56.      */
  57.     public OnClickListener getListener() {
  58.         return this.listener;
  59.     }
  60. }
复制代码
接下来就是这个弹窗的实现了,我们继承PopupWindow类。在这个类中我们需要实现通过位置设置动画及弹出位置,并且给出一个方法供实现类调用,来动态添加item和设置动画效果。
代码如下:
  1. /**
  2. * 继承弹窗,构造我们需要的弹窗
  3. */
  4. public class QuickActions extends PopupWindow {

  5.     private final View            root;
  6.     private final ImageView       mArrowUp;
  7.     private final ImageView       mArrowDown;
  8.     private final Animation       mTrackAnim;
  9.     private final LayoutInflater  inflater;
  10.     private final Context         context;

  11.     protected final View          anchor;
  12.     protected final PopupWindow   window;
  13.     private Drawable              background            = null;
  14.     protected final WindowManager windowManager;

  15.     protected static final int    ANIM_GROW_FROM_LEFT   = 1;
  16.     protected static final int    ANIM_GROW_FROM_RIGHT  = 2;
  17.     protected static final int    ANIM_GROW_FROM_CENTER = 3;
  18.     protected static final int    ANIM_AUTO             = 4;

  19.     private int                   animStyle;
  20.     private boolean               animateTrack;
  21.     private ViewGroup             mTrack;
  22.     private ArrayList<ActionItem> actionList;

  23.     /**
  24.      * 构造器,在这里初始化一些内容
  25.      * 
  26.      * @param anchor 像我之前博客所说的理解成一个基准 弹窗以此为基准弹出
  27.      */
  28.     public QuickActions(View anchor) {
  29.         super(anchor);

  30.         this.anchor = anchor;
  31.         this.window = new PopupWindow(anchor.getContext());

  32.         // 在popwindow外点击即关闭该window
  33.         window.setTouchInterceptor(new OnTouchListener() {

  34.             @Override
  35.             public boolean onTouch(View v, MotionEvent event) {
  36.                 if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
  37.                     QuickActions.this.window.dismiss();

  38.                     return true;
  39.                 }

  40.                 return false;
  41.             }
  42.         });

  43.         // 得到一个windowManager对象,用来得到窗口的一些属性
  44.         windowManager = (WindowManager) anchor.getContext().getSystemService(Context.WINDOW_SERVICE);

  45.         actionList = new ArrayList<ActionItem>();
  46.         context = anchor.getContext();
  47.         inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

  48.         // 装载布局,root即为弹出窗口的布局
  49.         root = (ViewGroup) inflater.inflate(R.layout.quickaction, null);

  50.         // 得到上下两个箭头
  51.         mArrowDown = (ImageView) root.findViewById(R.id.arrow_down);
  52.         mArrowUp = (ImageView) root.findViewById(R.id.arrow_up);

  53.         setContentView(root);

  54.         mTrackAnim = AnimationUtils.loadAnimation(anchor.getContext(), R.anim.rail);

  55.         // 设置动画的加速效果
  56.         mTrackAnim.setInterpolator(new Interpolator() {

  57.             public float getInterpolation(float t) {

  58.                 final float inner = (t * 1.55f) - 1.1f;

  59.                 return 1.2f - inner * inner;
  60.             }
  61.         });

  62.         // 这个是弹出窗口内的水平布局
  63.         mTrack = (ViewGroup) root.findViewById(R.id.tracks);
  64.         animStyle = ANIM_AUTO;// 设置动画风格
  65.         animateTrack = true;
  66.     }

  67.     /**
  68.      * 设置一个flag来标识动画显示
  69.      */
  70.     public void animateTrack(boolean animateTrack) {
  71.         this.animateTrack = animateTrack;
  72.     }

  73.     /**
  74.      * 设置动画风格
  75.      */
  76.     public void setAnimStyle(int animStyle) {
  77.         this.animStyle = animStyle;
  78.     }

  79.     /**
  80.      * 增加一个action
  81.      */
  82.     public void addActionItem(ActionItem action) {
  83.         actionList.add(action);
  84.     }

  85.     /**
  86.      * 弹出弹窗
  87.      */
  88.     public void show() {
  89.         // 预处理,设置window
  90.         preShow();

  91.         int[] location = new int[2];
  92.         // 得到anchor的位置
  93.         anchor.getLocationOnScreen(location);

  94.         // 以anchor的位置构造一个矩形
  95.         Rect anchorRect = new Rect(location[0], location[1], location[0] + anchor.getWidth(), location[1]
  96.                                                                                               + anchor.getHeight());

  97.         root.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
  98.         root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

  99.         int rootWidth = root.getMeasuredWidth();
  100.         int rootHeight = root.getMeasuredHeight();

  101.         // 得到屏幕的宽
  102.         int screenWidth = windowManager.getDefaultDisplay().getWidth();

  103.         // 设置弹窗弹出的位置的x/y
  104.         int xPos = (screenWidth - rootWidth) / 2;
  105.         int yPos = anchorRect.top - rootHeight;

  106.         boolean onTop = true;

  107.         // 在底部弹出
  108.         if (rootHeight > anchorRect.top) {
  109.             yPos = anchorRect.bottom;
  110.             onTop = false;
  111.         }

  112.         // 根据弹出位置,设置不同方向箭头图片
  113.         showArrow(((onTop) ? R.id.arrow_down : R.id.arrow_up), anchorRect.centerX());

  114.         // 设置弹出动画风格
  115.         setAnimationStyle(screenWidth, anchorRect.centerX(), onTop);

  116.         // 创建action list
  117.         createActionList();

  118.         // 在指定位置弹出弹窗
  119.         window.showAtLocation(this.anchor, Gravity.NO_GRAVITY, xPos, yPos);

  120.         // 设置弹窗内部的水平布局的动画
  121.         if (animateTrack) mTrack.startAnimation(mTrackAnim);
  122.     }

  123.     /**
  124.      * 预处理窗口
  125.      */
  126.     protected void preShow() {
  127.         if (root == null) {
  128.             throw new IllegalStateException("需要为弹窗设置布局");
  129.         }

  130.         // 背景是唯一能确定popupwindow宽高的元素,这里使用root的背景,但是需要给popupwindow设置一个空的BitmapDrawable
  131.         if (background == null) {
  132.             window.setBackgroundDrawable(new BitmapDrawable());
  133.         } else {
  134.             window.setBackgroundDrawable(background);
  135.         }

  136.         window.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
  137.         window.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
  138.         window.setTouchable(true);
  139.         window.setFocusable(true);
  140.         window.setOutsideTouchable(true);
  141.         // 指定布局
  142.         window.setContentView(root);
  143.     }

  144.     /**
  145.      * 设置动画风格
  146.      * 
  147.      * @param screenWidth 屏幕宽底
  148.      * @param requestedX 距离屏幕左边的距离
  149.      * @param onTop 一个flag用来标识窗口的显示位置,如果为true则显示在anchor的顶部
  150.      */
  151.     private void setAnimationStyle(int screenWidth, int requestedX, boolean onTop) {
  152.         // 取得屏幕左边到箭头中心的位置
  153.         int arrowPos = requestedX - mArrowUp.getMeasuredWidth() / 2;
  154.         // 根据animStyle设置相应动画风格
  155.         switch (animStyle) {
  156.             case ANIM_GROW_FROM_LEFT:
  157.                 window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left);
  158.                 break;

  159.             case ANIM_GROW_FROM_RIGHT:
  160.                 window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right);
  161.                 break;

  162.             case ANIM_GROW_FROM_CENTER:
  163.                 window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center);
  164.                 break;

  165.             case ANIM_AUTO:
  166.                 if (arrowPos <= screenWidth / 4) {
  167.                     window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left);
  168.                 } else if (arrowPos > screenWidth / 4 && arrowPos < 3 * (screenWidth / 4)) {
  169.                     window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center);
  170.                 } else {
  171.                     window.setAnimationStyle((onTop) ? R.style.Animations_PopDownMenu_Right : R.style.Animations_PopDownMenu_Right);
  172.                 }

  173.                 break;
  174.         }
  175.     }

  176.     /**
  177.      * 创建action list
  178.      */
  179.     private void createActionList() {
  180.         View view;
  181.         String title;
  182.         Drawable icon;
  183.         OnClickListener listener;
  184.         int index = 1;

  185.         for (int i = 0; i < actionList.size(); i++) {
  186.             title = actionList.get(i).getTitle();
  187.             icon = actionList.get(i).getIcon();
  188.             listener = actionList.get(i).getListener();
  189.             // 得到action item
  190.             view = getActionItem(title, icon, listener);

  191.             view.setFocusable(true);
  192.             view.setClickable(true);

  193.             // 将其加入布局
  194.             mTrack.addView(view, index);

  195.             index++;
  196.         }
  197.     }

  198.     /**
  199.      * 获得 action item
  200.      * 
  201.      * @param title action的标题
  202.      * @param icon action的图标
  203.      * @param listener action的点击事件监听器
  204.      * @return action的item
  205.      */
  206.     private View getActionItem(String title, Drawable icon, OnClickListener listener) {
  207.         // 装载action布局
  208.         LinearLayout container = (LinearLayout) inflater.inflate(R.layout.action_item, null);
  209.         ImageView img = (ImageView) container.findViewById(R.id.icon);
  210.         TextView text = (TextView) container.findViewById(R.id.title);

  211.         if (icon != null) {
  212.             img.setImageDrawable(icon);
  213.         } else {
  214.             img.setVisibility(View.GONE);
  215.         }

  216.         if (title != null) {
  217.             text.setText(title);
  218.         } else {
  219.             text.setVisibility(View.GONE);
  220.         }

  221.         if (listener != null) {
  222.             container.setOnClickListener(listener);
  223.         }

  224.         return container;
  225.     }

  226.     /**
  227.      * 显示箭头
  228.      * 
  229.      * @param 箭头资源id
  230.      * @param 距离屏幕左边的距离
  231.      */
  232.     private void showArrow(int whichArrow, int requestedX) {
  233.         final View showArrow = (whichArrow == R.id.arrow_up) ? mArrowUp : mArrowDown;
  234.         final View hideArrow = (whichArrow == R.id.arrow_up) ? mArrowDown : mArrowUp;

  235.         final int arrowWidth = mArrowUp.getMeasuredWidth();

  236.         showArrow.setVisibility(View.VISIBLE);

  237.         ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams) showArrow.getLayoutParams();

  238.         // 以此设置距离左边的距离
  239.         param.leftMargin = requestedX - arrowWidth / 2;

  240.         hideArrow.setVisibility(View.INVISIBLE);
  241.     }

  242. }
复制代码
有点长,不过注释都写的很清楚了。show()方法完成窗口的弹出。里面调用其他方法设置了窗口弹出的位置,设置了相应的动画弹出风格和箭头朝向以及位置,创建了action item。大家可以从这个方法里开始看,看每个的实现。
  最后写个测试类。放一个Button在屏幕顶部,一个在屏幕底部。点击弹出弹窗。
  1. package com.notice.quickaction;

  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.view.View;
  5. import android.view.View.OnClickListener;
  6. import android.widget.Button;
  7. import android.widget.Toast;

  8. /**
  9. * 实现activity
  10. */
  11. public class MyQuick extends Activity {

  12.     @Override
  13.     public void onCreate(Bundle savedInstanceState) {
  14.         super.onCreate(savedInstanceState);

  15.         setContentView(R.layout.main);

  16.         // 得到一个actionItem对象
  17.         final ActionItem chart = new ActionItem();

  18.         // 设置标题,图标,点击事件
  19.         chart.setTitle("Chart");
  20.         chart.setIcon(getResources().getDrawable(R.drawable.chart));
  21.         chart.setOnClickListener(new OnClickListener() {

  22.             @Override
  23.             public void onClick(View v) {
  24.                 Toast.makeText(MyQuick.this, "Chart selected", Toast.LENGTH_SHORT).show();
  25.             }
  26.         });

  27.         final ActionItem production = new ActionItem();

  28.         production.setTitle("Products");
  29.         production.setIcon(getResources().getDrawable(R.drawable.production));
  30.         production.setOnClickListener(new OnClickListener() {

  31.             @Override
  32.             public void onClick(View v) {
  33.                 Toast.makeText(MyQuick.this, "Products selected", Toast.LENGTH_SHORT).show();
  34.             }
  35.         });

  36.         Button btn1 = (Button) this.findViewById(R.id.btn1);
  37.         // 点击按钮弹出
  38.         btn1.setOnClickListener(new View.OnClickListener() {

  39.             @Override
  40.             public void onClick(View v) {
  41.                 // 初始化一个QuickActions
  42.                 QuickActions qa = new QuickActions(v);
  43.                 // 为他添加actionitem
  44.                 qa.addActionItem(chart);
  45.                 qa.addActionItem(production);
  46.                 qa.addActionItem(production);
  47.                 qa.addActionItem(production);
  48.                 // 设置动画风格
  49.                 qa.setAnimStyle(QuickActions.ANIM_AUTO);

  50.                 qa.show();
  51.             }
  52.         });

  53.         final ActionItem dashboard = new ActionItem();

  54.         dashboard.setIcon(getResources().getDrawable(R.drawable.dashboard));
  55.         dashboard.setOnClickListener(new OnClickListener() {

  56.             @Override
  57.             public void onClick(View v) {
  58.                 Toast.makeText(MyQuick.this, "dashboard selected", Toast.LENGTH_SHORT).show();
  59.             }
  60.         });

  61.         final ActionItem users = new ActionItem();

  62.         users.setIcon(getResources().getDrawable(R.drawable.users));
  63.         users.setOnClickListener(new OnClickListener() {

  64.             @Override
  65.             public void onClick(View v) {
  66.                 Toast.makeText(MyQuick.this, "Products selected", Toast.LENGTH_SHORT).show();
  67.             }
  68.         });

  69.         Button btn2 = (Button) this.findViewById(R.id.btn2);
  70.         btn2.setOnClickListener(new OnClickListener() {

  71.             @Override
  72.             public void onClick(View v) {
  73.                 QuickActions qa = new QuickActions(v);

  74.                 qa.addActionItem(dashboard);
  75.                 qa.addActionItem(users);
  76.                 qa.setAnimStyle(QuickActions.ANIM_GROW_FROM_CENTER);

  77.                 qa.show();
  78.             }
  79.         });
  80.     }
  81. }
复制代码
再讲下PopupWindow的风格的实现。其中一个风格代码如下:
  1. <style name="Animations.PopDownMenu.Left">
  2.         <item name="@android:windowEnterAnimation">@anim/grow_from_topleft_to_bottomright</item>
  3.         <item name="@android:windowExitAnimation">@anim/shrink_from_bottomright_to_topleft</item>
  4.     </style>
复制代码
写两个item,分别实现弹出和消失动画。因为篇幅有限(好像已经很长了。。。),就不全部贴出来了。动画都是一个scale加一个alpha,对动画不熟悉的朋友可以自己研究下,从底部弹出的动画文件grow_from_bottom.xml:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <set xmlns:android="http://schemas.android.com/apk/res/android">
  3.     <scale
  4.         android:fromXScale="0.3" android:toXScale="1.0"
  5.         android:fromYScale="0.3" android:toYScale="1.0"
  6.         android:pivotX="50%" android:pivotY="100%"
  7.         android:duration="@android:integer/config_shortAnimTime"
  8.     />
  9.     <alpha
  10.         android:interpolator="@android:anim/decelerate_interpolator"
  11.         android:fromAlpha="0.0" android:toAlpha="1.0"
  12.         android:duration="@android:integer/config_shortAnimTime"
  13.     />
  14. </set>
复制代码
最后来看看实现效果:


  333.jpg
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 实木椅子腿断了怎么办 铁质椅子腿断了怎么办 大套摩托车查车怎么办 摩托车本扣12分怎么办 蓝牙耳机上面的软套掉了怎么办 工作不想干了怎么办啊 浴室门玻璃坏了怎么办 电梯顶层安全安全距离不合格怎么办 制冰机有些孔不出水怎么办 制冰机排水孔堵住了怎么办 点我达装备抽查怎么办 空军常服大檐帽有一点变形怎么办 一般纳税人没有进项发票怎么办 汽车购买发票丢了怎么办 购买房子的发票丢了怎么办 购买的二手房发票丢失怎么办 购买空调时的发票丢失怎么办 发票购票本丢了怎么办 留学中介费贵了怎么办 车祸伤者不肯出院怎么办 增值税普通发票发票联丢失怎么办 纳税识别号错了怎么办 电子发票税号填写错误怎么办 发票抬头名称写错了怎么办 滴滴发票抬头写错了怎么办 普票抬头开错了怎么办 发票号码打错了怎么办 个人税票开错了怎么办 普票地址错了怎么办 专票税率开高了怎么办 专票税率开错了怎么办 发票姓名写错了怎么办 首付发票姓名写错怎么办 一般纳税人税率开错了怎么办 电子税票开错了怎么办 税率是6%开成3%怎么办 医院收费收错了怎么办 发票少打一个字怎么办 增值税发票抬头错了一个字怎么办 暂估入账跨年了怎么办 电子发票写错了怎么办