精华内容
下载资源
问答
  • **简评:**2018 年秋季,苹果公司推出了 iOS 12,其中...在一个 Reddit 话题中,父母们分享了他们的孩子如何绕过 Apple 的「屏幕时间限制」。 一位父亲引起了该话题的讨论,他的儿子找到了解决屏幕时间限制的方法 ...

    **简评:**2018 年秋季,苹果公司推出了 iOS 12,其中备受好评的一项改变是:增加了屏幕使用时间限制,以减轻沉迷手机的状况。三个月过去后,这项功能似乎并没有对孩子造成太多困扰,道高一尺魔高一丈,孩子们很快就找到了应对方法。

    在一个 Reddit 话题中,父母们分享了他们的孩子如何绕过 Apple 的「屏幕时间限制」。

    一位父亲引起了该话题的讨论,他的儿子找到了解决屏幕时间限制的方法 —— 当他的孩子在游戏中达到时间限制时,他只需删除该应用,然后重新下载就可以了。

    他父亲表示:我还能说什么呢?龟儿子太聪明了,我都生不起气,甚至还有点佩服……

    而为了绕过 YouTube 的时间限制,另一个孩子会在 iMessage 中发送自己的 YouTube 链接。然后,即使当 YouTube 使用时间被限制后,他也可以在 iMessage 应用中观看这个视频。

    在这个 9000 多 upvotes 的话题中,大人们发现,早在 Apple 推出屏幕时间之前,孩子们就一直在寻找方法来绕过父母限制他们玩手机的规则。甚至还有些人编写程序来覆盖或破解密码,然后在一天结束时重新设置所有内容(这个有点厉害)。

    突然想起了小时候在家偷看电视的经历 ?


    原文链接:Reddit | My kid managed to pass Screen time limit

    展开全文
  • 首先感谢大神JessYan的创神之作《AndroidAutoSize》,大神以今日头条屏幕适配的核心代码为基础进行了扩展封装,产生了《AndroidAutoSize》这个能快速接入使用屏幕适配方案,这个屏幕适配方案是我遇到的截止2020.9....

    Android 第三方库系列文章

    1. Android 今日头条屏幕适配详细使用攻略
    2. Lottie动画 轻松使用

    博客创建时间:2020.09.20
    博客更新时间:2021.06.27

    以Android studio build=4.2.1,gradle=6.7.1,SdkVersion 30来分析讲解。如图文和网上其他资料不一致,可能是别的资料版本较低而已


    前言

    首先感谢大神JessYan的创神之作《AndroidAutoSize》,大神以今日头条屏幕适配的核心代码为基础进行了扩展封装,产生了《AndroidAutoSize》这个能快速接入使用的屏幕适配方案,这个屏幕适配方案是我遇到的截止2020.9.15为止最强大、简单有效的屏幕适配方案。我已使用该方案有一年,在使用过程未发现有何问题,强烈推荐各位极客们使用学习。

    以下是大神JessYan的相关地址:

    大神的源码都在github中各位可以自行下载,我写这篇博客的目的就是记录使用心得,并将该框架的重要类和方法使用进行详细说明,大神的文章中对细节问题写的比较少,我对其进行了细微的修改和详细的注解解释。我自己修改注释过得框架源码请前往github下载https://github.com/l424533553/MyAutoSize


    1. 屏幕像素

    像素
    通常所说的像素,就是CCD/CMOS上光电感应元件的数量,一个感光元件经过感光,光电信号转换,A/D转换等步骤以后,在输出的照片上就形成一个点,我们如果把影像放大数倍,会发现这些连续色调其实是由许多色彩相近的小方点所组成,这些小方点就是构成影像的最小单位“像素”(Pixel)。简而言之,像素就是手机屏幕的最小构成单元。

    屏幕尺寸
    屏幕尺寸指屏幕的对角线的长度,单位是英寸,1英寸=2.54厘米。比如常见的屏幕尺寸有2.4、2.8、3.5、3.7、4.2、5.0、5.5、6.0等

    屏幕分辨率
    屏幕分辨率是指在横纵向上的像素点数,单位是px,1px=1个像素点。一般以纵向像素横向像素,如19201080

    屏幕像素密度(dpi)
    屏幕像素密度是指每英寸上的像素点数,单位是dpi,即“dot per inch”的缩写。屏幕像素密度与屏幕尺寸和屏幕分辨率有关,在单一变化条件下,屏幕尺寸越小、分辨率越高,像素密度越大,反之越小。
    在这里插入图片描述

    计算公式: 像素密度 = 像素 / 尺寸 (dpi = px / in)
    标准屏幕像素密度(mdpi): 每英寸长度上还有160个像素点(160dpi),即称为标准屏幕像素密度(mdpi)。

    密度无关像素(dp)
    含义:density-independent pixel,叫dp或dip,与终端上的实际物理像素点无关
    单位:dp,可以保证在不同屏幕像素密度的设备上显示相同的效果,是安卓特有的长度单位。
    场景例子:假如同样都是画一条长度是屏幕一半的线,如果使用px作为计量单位,那么在480x800分辨率手机上设置应为240px;在320x480的手机上应设置为160px,二者设置就不同了;如果使用dp为单位,在这两种分辨率下,160dp都显示为屏幕一半的长度。
    dp与px的转换:1dp = (dpi / 160 ) * 1px;

    密度类型 代表的分辨率(px) 屏幕像素密度(dpi) 换算
    低密度(ldpi) 240 x 320 120 1dp = 0.75px
    中密度(mdpi) 320 x 480 160 1dp = 1px
    高密度(hdpi) 480 x 800 240 1dp = 1.5px
    超高密度(xhdpi) 720 x 1280 320 1dp = 2px
    超超高密度(xxhdpi) 1080 x 1920 480 1dp = 3px

    独立比例像素(sp)
    scale-independent pixel,叫sp或sip,字体大小专用单位 ,Android开发时用此单位设置文字大小,可根据字体大小首选项进行缩放。
    推荐使用12sp、14sp、18sp、22sp作为字体大小,不推荐使用奇数和小数,容易造成精度丢失,12sp以下字体太小。

    sp与dp的区别
    dp只跟屏幕的像素密度有关, sp和dp很类似但唯一的区别是,Android系统允许用户自定义文字尺寸大小(小、正常、大、超大等等),当文字尺寸是“正常”时1sp=1dp=0.00625英寸,而当文字尺寸是“大”""或“超大”时,1sp>1dp=0.00625英寸。类似我们在windows里调整字体尺寸以后的效果——窗口大小不变,只有文字大小改变。


    2. 适配原理

    传统的屏幕适配头如下几种措施:

    1. 种像素密度机型,做5套图。比例 1:1.5:2:3:4
    2. 多用相对布局
    3. 尺寸限定符
    4. 点九图
    5. 不同图片填充类型ScaleType
      但是以往的所有屏幕适配都有各种各样的问题和重大缺陷,直到字节跳动的屏幕适配方案出现。根据其公开的核心源码,网上重大大咖封装了各种屏幕适配框架,其中最成功且本人使用感受最好的是AutoSize框架。

    Android AutoSize的核心代码来源于字节跳动的微信文章https://mp.weixin.qq.com/s/d9QCoBP6kV9VSWvVldVVwA。网上也有多各个大神进行了代码的封装设计,都是万变不离其中。

    1. 核心思想

            DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
            if (sNoncompatDensity == 0) {
                sNoncompatDensity = appDisplayMetrics.density;
                sNoncompatDensity = appDisplayMetrics.scaledDensity;
                application.registerComponentCallbacks(new ComponentCallbacks() {
                    
                    public void onConfigurationChanged(Configuration newConfig) {
                        if (newConfig != null && newConfig.fontScale > 0) {
                            sNoncompatScaledDensity = application.getResources().getDisplayMetrics().scaledDensity;
                        }
                    }
    
                    
                    public void onLowMemory() {
    
                    }
                });
            }
            float targetDensity = appDisplayMetrics.widthPixels / 360;
            float targetScaleDensity = targetDensity * (sNoncompatScaledDensity / sNoncompatDensity);
            int targetDensityDpi = (int) (160 * targetDensity);
            appDisplayMetrics.density = targetDensity;
            appDisplayMetrics.scaledDensity = targetScaleDensity;
            appDisplayMetrics.densityDpi = targetDensityDpi;
    
            final DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
            activityDisplayMetrics.density = targetDensity;
            activityDisplayMetrics.scaledDensity = targetScaleDensity;
            activityDisplayMetrics.densityDpi = targetDensityDpi;
    

    原理很简单,例如一个4.59的10801920的手机它的dpi=480,它的density=480/160,则说明1dp=3px。当我们在布局中给如TextView设置layout_width=30dp时,在程序运行时会自动计算其对应px单位长度90px,px=dpdensity。

    今日头条适配方案的核心就是动态计算程序中的density=appDisplayMetrics.widthPixels / 360,360是原始设计图纸的dp。假设原先的设计图纸10801920,现在适配5.99寸560dpi的14402880手机,则30dp=30560/160=105px,实际上屏幕适配要求的30dp=1440/36030=120px才可以达到适配效果。因为120/1440=90/1080,控件在布局中的占宽比是一样的才能达到宽度适配效果。这就是为什么要动态修改全局或activity的DisplayMetrics#density的目的了。


    2. 优缺点

    • 优点:
    1. 侵入性非常低,该方案和项目完全解耦,使用的还是Android官方单位
    2. 接入无性能损耗,使用的全是Android官方的API。
    • 缺点:
    1. 项目中的系统控件、三方库控件、等非我们项目自身设计的控件,它们的设计图尺寸并不会和我们项目自身的设计图尺寸一样,此时会产生适配误差。解决方案就是取消当前 Activity 的适配效果,改用其他的适配方案
    2. 系统修改字体大小后,返回应用系统字体大小还是未改变,需要设置registerComponentCallbacks监听。 Android AutoSize框架已经解决了该问题。
    3. 在使用过程中需要进行registerComponentCallbacks监听内容文字的大小改变情况,解决退出应用修改文字大小后,文字大小不改变的情况。

    3. 框架配置

    依赖配置

    1. 远程依赖,截止到2020.9.15,版本为1.2.1
        implementation 'me.jessyan:autosize:1.2.1'
    
    1. 从github上下载源码进行library库依赖

    参数配置
    在AndroidManifest.xml中配置参数

    <manifest>
        <application>    
            ...
            <meta-data
                android:name="design_width_in_dp"
                android:value="360"/>
            <meta-data
                android:name="design_height_in_dp"
                android:value="640"/>      
            ...
         </application>           
    </manifest>
    

    4. 自定义初始化

    本文中使用的框架是经过大神JessYan的封装后成为你所看到的框架。它能根据一套给定的设计图尺寸进行布局展示,当安装当不同分辨率尺寸的设备上时,它能自动适配屏幕。

    框架的初始化时机是配置在ContentProvider中,在Application#onCreate()方法之前启动。框架一旦初始化完成,其适配效果会在Activity和Fragment、各种View中自动全局适配。程序将默认是以屏幕宽度为基准进行适配的,并且使用的是在AndroidManifest中填写的全局设计图尺寸进行全局适配。

    框架支持dp、sp两个主单位,pt、in、mm三个冷门副单位,如果使用副单位,可以规避系统控件或三方库控件使用的不良影响。

    ContentProvider初始化第三方库
    ContentProvider是一种共享型组件,它通过Binder向其他组件或者其他应用程序提供数据,当ContentProvider所在进程启动时候,ContentProvider会被同时启动并被发布到AMS中。

    ContentProvider的onCreate要优先于Application的onCreate,但在attachBaseContext()之后而执行,它的具体详细启动源码在ActivityThread中。很多人会在ContentProvider#onCreate()初始化第三方库。

    一般进行了依赖配置参数配置两操作,Android AutoSize就配置完成可以直接使用了,它的框架源码初始化在InitProvider代码中。

    在InitProvider 中已进行了初始化设置

    public class InitProvider extends ContentProvider {
        @Override
        public boolean onCreate() {
            if (getContext() != null) {
                Context application = getContext().getApplicationContext();
                if (application == null) {
                    application = AutoSizeUtils.getApplicationByReflect();
                }
                AutoSizeConfig.getInstance()
                        .setLog(true)
                        .init((Application) application)
                        .setUseDeviceSize(false);
                return true;
            }
            return false;
        }
    

    但是为了个性化的配置,我们可以在Application中进行一些自定义设置,设置的方法都应写在Application#onCreate()方法中。

    public class Application {
        @Override
        public void onCreate() {
            super.onCreate();
            ...
            AutoSize.initCompatMultiProcess(this);
            AutoSize.checkAndInit(this);
            AutoSizeConfig.getInstance()
                    .setCustomFragment(true)
                    .setExcludeFontScale(true)
                    .setPrivateFontScale(0.8f)
                    .setLog(false)
                    .setBaseOnWidth(true)
                    .setUseDeviceSize(true)
                    //屏幕适配监听器
                    .setOnAdaptListener(new OnAdaptListener() {
                        @Override
                        public void onAdaptBefore(Object target, Activity activity) {
    //                        AutoSizeConfig.getInstance().setScreenWidth(ScreenUtils.getScreenSize(activity)[0]);
    //                        AutoSizeConfig.getInstance().setScreenHeight(ScreenUtils.getScreenSize(activity)[1]);
                            AutoSizeLog.d(String.format(Locale.ENGLISH, "%s onAdaptBefore!", target.getClass().getName()));
                        }
    
                        @Override
                        public void onAdaptAfter(Object target, Activity activity) {
                            AutoSizeLog.d(String.format(Locale.ENGLISH, "%s onAdaptAfter!", target.getClass().getName()));
                        }
                    });
            configUnits();
        }
        
        private void configUnits() {
            AutoSizeConfig.getInstance()
                    .getUnitsManager()
                    .setSupportDP(true)
                    .setDesignSize(2160, 3840)
                    .setSupportSP(true)
                    .setSupportSubunits(Subunits.MM);
        }
    }
    

    5. 常用方法解析

    对于初始化中方法,我们进行一一分析
    1. AutoSize.initCompatMultiProcess(Context context)
    当 App 中出现多进程,并且您需要适配所有的进程,就需要在 App 初始化时调用。一般的单进程App程序不用设置。

    2. AutoSize.checkAndInit(Application application)

         if (!checkInit()) {
                AutoSizeConfig.getInstance()
                        .setLog(true)
                        .init(application)
                        .setUseDeviceSize(false);
            }
    

    一般来说Android AutoSize会通过InitProvider实例化自动完成初始化,是不需要调用checkAndInit()方法的。但由于某些 issues 反应, 可能会在某些特殊情况下出现InitProvider未能正常实例化的情况, 导致 AndroidAutoSize 未能完成初始化。所以需要使用该方法确保Android AutoSize 初始化成功。

    3. AutoSizeConfig.getInstance().setCustomFragment(boolean customFragment)
    设定是否让框架支持自定义Fragment 的适配参数,一般这个需求比较少。默认不支持的

    4. AutoSizeConfig.getInstance().setExcludeFontScale(true)
    是否屏蔽系统字体大小对AndroidAutoSize 的影响, 如果为 true, App 内的字体的大小将不会跟随系统设置中字体大小的改变, 如果为 false, 则会跟随系统设置中字体大小的改变, 默认为 false

    5. AutoSizeConfig.getInstance().setPrivateFontScale(float fontScale)
    区别于系统字体大小的放大比例, AndroidAutoSize 允许 APP 内部可以独立于系统字体大小之外,独自拥有全局调节 APP 字体大小的能力。 fontScale取值0~1,设为 0 则取消此功能。同时字体的单位必须是sp做单位。

    6. AutoSizeConfig.getInstance().setLog(boolean log)
    设置是否打印AutoSize的日志,true为打印

    7. AutoSizeConfig.getInstance().setBaseOnWidth(true)
    是否全局按照宽度进行等比例适配,true以宽来适配,false以高来适配

    8. AutoSizeConfig.getInstance().stop(this)
    自动适配方案可以手动调用方法停止,需要注意的是Android AutoSize暂停只是停止了对后续还没有启动的{@link Activity}进行适配的工作,但对已经启动且已经适配的{@link Activity}不会有任何影响

    9. AutoSizeConfig.getInstance().restart()
    AutoSize可以暂停适配也可以重启适配,但是重启适配只能对后续还没有启动的 {@link Activity} 进行适配的工作,但对已经启动且在stop期间未适配的{@link Activity}不会有任何影响

    10. AutoSizeConfig.getInstance().setUseDeviceSize(true)
    是否以屏幕的实际尺寸为高度,默认为false,屏幕的适配高度是屏幕总高度减去状态栏高度。

    11. UnitsManager.setSupportSP(boolean supportSP)
    是否让框架支持sp单位,默认是为true支持,如果为false,则字体大小最好设置为其他单位才能自动适配

    12. UnitsManager.setSupportSubunits(Subunits supportSubunits)
    自主设置心仪的副单位,可以从pt、in、mm中进行选择,如果使用了Subunits#NONE即代表不支持副单位

    13. UnitsManager.setSupportDP(boolean supportDP)
    是否支持dp单位,默认是true支持,如果关闭将不对dp单位进行支持

    14. UnitsManager.setDesignSize(float designWidth, float designHeight)
    设置设计图尺寸,一般专为副单位尺寸设计,它与AndroidManifest.xml中配置的参数不一样,不会被覆盖。


    6. 常见接口及类的使用

    CustomAdapt
    实现CustomAdapt接口即可对activity和fragment进行新的自定义尺寸适配,适配方向可以自主选择是宽度还是高度。实现该接口会取消默认的适配方案和效果。对于fragment的自定义尺寸需要进AutoSizeConfig.getInstance().setCustomFragment(true)设置,默认是不支持对fragment的自定义尺寸适配的。

    <在CustomAdapt接口中需要实现者重写两个方法boolean isBaseOnWidth()和float getSizeInDp(),根据使用者需求自定义。

    • 1. boolean isBaseOnWidth()
      为了保证在高宽比不同的屏幕上也能正常适配,所以只能在宽度和高度之中选一个作为基准进行适配。 true为按照宽度适配, false 为按照高度适配

    • 2. float getSizeInDp()
      getSizeInDp 须配合isBaseOnWidth()使用, 有如下使用规则:
      如果 {@link #isBaseOnWidth()} 返回 {@code true}, {@link CustomAdapt #getSizeInDp} 则应该返回设计图的总宽度。
      如果 {@link #isBaseOnWidth()} 返回 {@code false}, {@link CustomAdapt #getSizeInDp} 则应该返回设计图的总高度。
      如果您不需要自定义设计图上的设计尺寸, 想继续使用在 AndroidManifest 中填写的设计图尺寸,getSizeInDp 则返回 0即可。

    CancelAdapt
    接口CancelAdapt没有任何成员变量,支持AndroidAutoSize的项目所有模块默认使用适配功能,第三方库的也不例外。
    如果某个页面不想使用适配功能, 请让该页面实现CancelAdapt接口放弃适配,所有的适配效果都将失效。


    7.框架核心

    1. 自定义适配
    通过字节跳动的核心源码,只能进行全局适配,但是该框架中进行了Activity和Fragmen的自定义适配和随时取消恢复适配功能。它的原理是注册了ActivityLifecycleCallbacks,进行了Activity的适配时间精准化自我掌控。

    通过注册ActivityLifecycleCallbacks,进行Activity的生命周期进行管理, 当onActivityCreated时,也就是OnCreate()的setContentView之前进行了AutoAdaptStrategy#applyAdapt的调用。这种方案类似于 AOP, 面向接口, 侵入性低, 方便统一管理, 扩展性强。

        @Override
        public void onActivityCreated(@androidx.annotation.NonNull Activity activity, Bundle savedInstanceState) {
            if (AutoSizeConfig.getInstance().isCustomFragment()) {
                if (mFragmentLifecycleCallbacksToAndroidx != null && activity instanceof androidx.fragment.app.FragmentActivity) {
                    ((androidx.fragment.app.FragmentActivity) activity).getSupportFragmentManager().registerFragmentLifecycleCallbacks(mFragmentLifecycleCallbacksToAndroidx, true);
                }
            }
            //Activity 中的 setContentView(View) 一定要在 super.onCreate(Bundle); 之后执行
            if (mAutoAdaptStrategy != null) {
                mAutoAdaptStrategy.applyAdapt(activity, activity);
            }
        }
    

    通过注册registerFragmentLifecycleCallbacks,进行Fragment的生命周期管理,当onFragmentCreated时,也就是OnCreate()中进行了AutoAdaptStrategy#applyAdapt的调用

    @Override
    public void onFragmentCreated(@androidx.annotation.NonNull FragmentManager fm, @androidx.annotation.NonNull Fragment f, Bundle savedInstanceState) {
            if (mAutoAdaptStrategy != null) {
                mAutoAdaptStrategy.applyAdapt(f, f.getActivity());
            }
        }
    
    

    通过全局的进行Activity和Fragment的生命周期监控,在其布局创建之前调用 AutoAdaptStrategy#applyAdapt进行具体的适配操作,它的关键点是动态修改density、scaledDensity、densityDpi三个参数,造成每个Activity或Fragment加载布局时的density、scaledDensity、densityDpi等参数不一样,达到的适配效果则不一样。


    2. 适配策略的实现
    ActivityLifecycleCallbacks的使用能实时监测Activity和Fragment进行适配调用,但是实际操作的代码在策略方案AutoAdaptStrategy的实现子类中,框架中已有默认策略方案,当然自己也可以自定义修改创建。

    • 当target实现CancelAdapt后,将density、scaledDensity、densityDpi恢复到原始状态,不进行匹配
    • 当target实现CustomAdapt后,将density、scaledDensity、densityDpi根据target的配置进行计算后设置
    • 当target未进行任何处理时,将density、scaledDensity、densityDpi根据AndroidManifest.xml中的配置进行计算设置
        @Override
        public void applyAdapt(Object target, Activity activity) {
        	....
            //如果 target 实现 CancelAdapt 接口表示放弃适配, 所有的适配效果都将失效
            if (target instanceof CancelAdapt) {
                AutoSizeLog.w(String.format(Locale.ENGLISH, "%s canceled the adaptation!", target.getClass().getName()));
                AutoSize.cancelAdapt(activity);
                return;
            }
    
            //如果 target 实现 CustomAdapt 接口表示该 target 想自定义一些用于适配的参数, 从而改变最终的适配效果
            if (target instanceof CustomAdapt) {
                AutoSizeLog.d(String.format(Locale.ENGLISH, "%s implemented by %s!", target.getClass().getName(), CustomAdapt.class.getName()));
                AutoSize.autoConvertDensityOfCustomAdapt(activity, (CustomAdapt) target);
            } else {
                AutoSizeLog.d(String.format(Locale.ENGLISH, "%s used the global configuration.", target.getClass().getName()));
                AutoSize.autoConvertDensityOfGlobal(activity);
            }
            ...
        }
       
    

    8. 其它

    1. Fragment横竖屏切换布局问题
    由于某些原因, 屏幕旋转后 Fragment 的重建, 会导致框架对 Fragment 的自定义适配参数失去效果。所以如果您的 Fragment 允许屏幕旋转, 则请在 onCreateView 手动调用一次 AutoSize.autoConvertDensity(),如AutoSize.autoConvertDensity(getActivity(), 1080, true)。
    如果您的 Fragment 不允许屏幕旋转, 则可以将下面调用 AutoSize.autoConvertDensity() 的代码删除掉

    public class CustomFragment1 extends Fragment implements CustomAdapt {
    
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            //由于某些原因, 屏幕旋转后 Fragment 的重建, 会导致框架对 Fragment 的自定义适配参数失去效果
            //所以如果您的 Fragment 允许屏幕旋转, 则请在 onCreateView 手动调用一次 AutoSize.autoConvertDensity()
            //如果您的 Fragment 不允许屏幕旋转, 则可以将下面调用 AutoSize.autoConvertDensity() 的代码删除掉
            AutoSize.autoConvertDensity(getActivity(), 1080, true);
            return createTextView(inflater, "Fragment-1\nView width = 360dp\nTotal width = 1080dp", 0xffff0000);
        }
    

    2. 主副单位的逐步替换
    框架中同时支持主单位和副单位,对于对于旧项目中已使用dp或px的项目,可以通过逐步在新页面中使用主单位副单位。通过不断的迭代替换,最终将项目中的主单位如dp全替换为副单位px,或者将副单位px全替换为主单位dp。

    当单位都替换完成后,设置UnitsManager.setSupportDP(false)关闭对dp的支持,彻底隔离修改 density 所造成的不良影响。
    或者都使用dp,不在支持副单位时设置UnitsManager.setSupportSubunits(Subunits.NONE)关闭对副单位的支持。

    3. 主副单位的同时支持
    当使用者想将旧项目从主单位过渡到副单位, 或从副单位过渡到主单位时。因为在使用主单位时, 建议在 AndroidManifest 中填写设计图的 dp 尺寸, 比如 360 * 640。

    但在 AndroidManifest 中却只能填写一套设计图尺寸, 并且已经填写了主单位的设计图尺寸,所以当项目中同时存在副单位和主单位, 并且副单位的设计图尺寸与主单位的设计图尺寸不同时, 可以通过UnitsManager#setDesignSize() 方法配置。

    如果副单位的设计图尺寸与主单位的设计图尺寸相同, 则不需要调用 UnitsManager#setDesignSize(), 框架会自动使用 AndroidManifest 中填写的设计图尺寸。

    4. 自定义单位模拟器创建
    布局时的实时预览在开发阶段是一个很重要的环节, 很多情况下 Android Studio 提供的默认预览设备并不能完全展示我们的设计图。所以我们就需要自己创建模拟设备, 大神@JessYan已经为我们准备好了dp、pt、in、mm 这四种单位的模拟设备创建方法,请点击查看链接https://github.com/JessYanCoding/AndroidAutoSize/blob/master/README-zh.md#preview


    总结

    经过我自己修改注释的源码在https://github.com/l424533553/MyAutoSize中,大家也可以自行封装框架,适合自己的才是最好的。

    屏幕自适应的核心就是根据需要在使用之前不断修改density、scaledDensity、densityDpi达到适配效果。


    相关链接

    1. Android 今日头条屏幕适配详细使用攻略
    2. Lottie动画 轻松使用

    扩展链接:

    1. Android CameraX 使用入门
    2. Android studio 最全必用插件
    3. Android 史上最新最全的ADB及命令百科,没有之一

    博客书写不易,您的点赞收藏是我前进的动力,千万别忘记点赞、 收藏 ^ _ ^ !

    展开全文
  • 使用 ActivityManager.AppTask 类来管理任务,使用 Intent 类的 Activity 标志来指定某 Activity 添加到概览屏幕或从中删除时间。此外,您也可以使用 <activity> 属性在清单文件中设置该行为。 Add tasks to ...

    Overview Screen(概览屏幕)简介

    概览屏幕(也称为最新动态屏幕、最近任务列表或最近使用的应用)是一个系统级别 UI,其中列出了最近访问过的Activity和任务。用户可以浏览该列表并选择要恢复的任务,也可以通过滑动清除任务将其从列表中删除。 对于 Android 5.0 版本(API 级别 21),包含多个文档的同一 Activity 的多个实例可能会以任务的形式显示在概览屏幕中。例如,Google Drive 可能对多个 Google 文档中的每个文档均执行一个任务。每个文档均以任务的形式显示在概览屏幕中。



    图 1. 显示了三个 Google Drive 文档的概览屏幕,每个文档分别以一个单独的任务表示。

    通常,您应该允许系统定义任务和 Activity 在概览屏幕中的显示方法,并且无需修改此行为。不过,应用可以确定 Activity 在概览屏幕中的显示方式和时间。 您可以使用 ActivityManager.AppTask 类来管理任务,使用 Intent 类的 Activity 标志来指定某 Activity 添加到概览屏幕或从中删除的时间。此外,您也可以使用 <activity> 属性在清单文件中设置该行为。

    Add tasks to the overview screen(将任务添加到概览屏幕)

    通过使用 Intent 类的标志添加任务,您可以更好地控制某文档在概览屏幕中打开或重新打开的时间和方式。使用 <activity> 属性时,您可以选择始终在新任务中打开文档,或选择对文档重复使用现有任务。

    1.使用 Intent 标志添加任务

    为 Activity 创建新文档时,可调用 ActivityManager.AppTask 类的 startActivity() 方法,以向其传递启动 Activity 的 Intent。要插入逻辑换行符以便系统将 Activity 视为新任务显示在概览屏幕中,可在启动 Activity 的 Intent 的 addFlags() 方法中传递FLAG_ACTIVITY_NEW_DOCUMENT标志。

    注:FLAG_ACTIVITY_NEW_DOCUMENT 标志取代了 FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET 标志,后者自 Android 5.0(API 级别 21)起已弃用。

    如果在创建新文档时设置 FLAG_ACTIVITY_MULTIPLE_TASK 标志,则系统始终会以目标 Activity 作为根创建新任务。此设置允许同一文档在多个任务中打开。以下代码演示了主 Activity 如何执行此操作:

    DocumentCentricActivity.java
    public void createNewDocument(View view) {
          final Intent newDocumentIntent = newDocumentIntent();
          if (useMultipleTasks) {
              newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
          }
          startActivity(newDocumentIntent);
      }
    
      private Intent newDocumentIntent() {
          boolean useMultipleTasks = mCheckbox.isChecked();
          final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class);
          newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
          newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, incrementAndGet());
          return newDocumentIntent;
      }
    
      private static int incrementAndGet() {
          Log.d(TAG, "incrementAndGet(): " + mDocumentCounter);
          return mDocumentCounter++;
      }
    }

    注:使用 FLAG_ACTIVITY_NEW_DOCUMENT 标志启动的 Activity 必须具有在清单文件中设置的android:launchMode="standard" 属性值(默认)。

    当主 Activity 启动新 Activity 时,系统会搜遍现有任务,看看是否有任务的 Intent 与 Activity 的 Intent 组件名称和 Intent 数据相匹配。 如果未找到任务或者 Intent 包含 FLAG_ACTIVITY_MULTIPLE_TASK 标志,则会以该 Activity 作为其根创建新任务。如果找到的话,则会将该任务转到前台并将新 Intent 传递给 onNewIntent()。新 Activity 将获得 Intent 并在概览屏幕中创建新文档,如下例所示:

    NewDocumentActivity.java:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_new_document);
        mDocumentCount = getIntent()
                .getIntExtra(DocumentCentricActivity.KEY_EXTRA_NEW_DOCUMENT_COUNTER, 0);
        mDocumentCounterTextView = (TextView) findViewById(
                R.id.hello_new_document_text_view);
        setDocumentCounterText(R.string.hello_new_document_counter);
    }
    
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        /* If FLAG_ACTIVITY_MULTIPLE_TASK has not been used, this activity
        is reused to create a new document.
         */
        setDocumentCounterText(R.string.reusing_document_counter);
    }
    

    2.使用 Activity 属性添加任务

    此外,Activity 还可以在其清单文件中指定始终通过使用 <activity> 属性 android:documentLaunchMode 进入新任务。 此属性有四个值,会在用户使用该应用打开文档时产生以下效果:

    (1)“intoExisting”
    该 Activity 会对文档重复使用现有任务。这与不设置 FLAG_ACTIVITY_MULTIPLE_TASK 标志、但设置FLAG_ACTIVITY_NEW_DOCUMENT 标志所产生的效果相同,如上文的使用 Intent 标志添加任务中所述。

    (2)“always”
    该 Activity 为文档创建新任务,即便文档已打开也是如此。使用此值与同时设置 FLAG_ACTIVITY_NEW_DOCUMENT 和 FLAG_ACTIVITY_MULTIPLE_TASK 标志所产生的效果相同。

    (3)“none”
    该 Activity 不会为文档创建新任务。概览屏幕将按其默认方式对待此 Activity:为应用显示单个任务,该任务将从用户上次调用的任意 Activity 开始继续执行。

    (4)“never”
    该 Activity 不会为文档创建新任务。设置此值会替代 FLAG_ACTIVITY_NEW_DOCUMENT 和 FLAG_ACTIVITY_MULTIPLE_TASK 标志的行为(如果在 Intent 中设置了其中一个标志),并且概览屏幕将为应用显示单个任务,该任务将从用户上次调用的任意 Activity 开始继续执行。

    注:对于除 none 和 never 以外的值,必须使用 launchMode="standard" 定义 Activity。如果未指定此属性,则使用 documentLaunchMode="none"。

    删除任务

    默认情况下,在 Activity 结束后,文档任务会从概览屏幕中自动删除。 您可以使用 ActivityManager.AppTask 类、Intent 标志或 <activity> 属性替代此行为。

    通过将 <activity> 属性 android:excludeFromRecents 设置为 true,您可以始终将任务从概览屏幕中完全排除。

    您可以通过将 <activity> 属性 android:maxRecents 设置为整型值,设置应用能够包括在概览屏幕中的最大任务数默认值为 16。达到最大任务数后,最近最少使用的任务将从概览屏幕中删除。 android:maxRecents 的最大值为 50(内存不足的设备上为 25);小于 1 的值无效。

    1.使用 AppTask 类删除任务

    在于概览屏幕创建新任务的 Activity 中,您可以通过调用 finishAndRemoveTask() 方法指定何时删除该任务以及结束所有与之相关的 Activity。

    NewDocumentActivity.java:
    public void onRemoveFromRecents(View view) {
        // The document is no longer needed; remove its task.
        finishAndRemoveTask();
    }

    注:如下所述,使用 finishAndRemoveTask() 方法代替使用 FLAG_ACTIVITY_RETAIN_IN_RECENTS 标记。

    2.保留已完成的任务

    若要将任务保留在概览屏幕中(即使其 Activity 已完成),可在启动 Activity 的 Intent 的 addFlags() 方法中传递 FLAG_ACTIVITY_RETAIN_IN_RECENTS 标志。

    DocumentCentricActivity.java:
    private Intent newDocumentIntent() {
        final Intent newDocumentIntent = new Intent(this, NewDocumentActivity.class);
        newDocumentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
          android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS);
        newDocumentIntent.putExtra(KEY_EXTRA_NEW_DOCUMENT_COUNTER, incrementAndGet());
        return newDocumentIntent;
    }

    要达到同样的效果,请将 <activity> 属性 android:autoRemoveFromRecents 设置为 false文档 Activity 的默认值为 true,常规 Activity 的默认值为 false。如前所述,使用此属性替代FLAG_ACTIVITY_RETAIN_IN_RECENTS 标志。




    本文是来自于Android Developer






    展开全文
  • SAP OO ALV 一个屏幕使用2个ALV

    万次阅读 2015-12-24 14:54:46
    终于完成了 OO ALV的学习,第一个作品。 一个屏幕上放了2个ALV控件,上面用来显示表头,下面用来显示详细的行项目。

    终于完成了 OO ALV的学习,第一个作品。 一个屏幕上放了2个ALV控件,上面用来显示表头,下面用来显示详细的行项目。

    业务背景:
    在汽车的售后服务环节,汽车零件在质保期内损坏,维修产生的费用,整车厂会追溯到零件供应商索取。

    数据模型简介:
    三包索赔单数据从销售系统中传入ERP系统。
    对三包索赔原始数据我们设计了2张表来存放,
    一张是表头表,存放三包索赔单号及相关信息,另一张是详细项目表,存放详细使用的零件项目。
    表头表和详细项目表的关系是一对多,即一条表头表(三包索赔单)对应多条详细项目(结算单)。


     ERP系统功能设计:

    物流部门需要对三包索赔单数据管理并打印出来发给供应商协商。
    1. ABAP程序需要在ERP系统中用2个ALV展示三包索赔数据和行项目,一条三包索赔数据对应多条详细项目。
    2. 选中ALV1中的一条三包索赔数据,ALV2中列出相关的详细项目。
    3.点击自定义按钮,完成对一个三包索赔单数据的审批和打印单据。


    ABAP代码说明:
    这次我们要实现一个屏幕放入2个ALV列表控件,点击第一个ALV控件(只能单选),带出数据放入第二个ALV控件中。

    使用FUNCTION ALV目前看来已经不能满足要求,需要用OO方式来控制ALV,这样就可以在一个屏幕上画上2个ALV。

    所以创建屏幕在所难免,我们创建一个屏幕0100,放2个自定义控件,取名CON1,CON2.


    屏幕会带出3个模块,所有这些模块代码,我选择全部放到一个源程序中,这样使用比较方便:

    PROCESS BEFORE OUTPUT.
     MODULE STATUS_0100.
     MODULE INIT_CON.
    PROCESS AFTER INPUT. 
     MODULE USER_COMMAND_0100.


    STATUS_0100 模块中,我们设置程序主画面的STAUTS,STAUTS是自己准备的,也可以用标准的。
    USER_COMMAND_0100 模块,就是对STAUTS上的绿,黄,红工具条按钮按下的效果。

    INIT_CON 模块中,是初始化屏幕和ALV控件,第一个ALV控件,我们会把数据也填充到内表,然后交有ALV显示出来。


    该模块中,我们可以看到OO ALV的使用方法,即CREATE OBJECT CON1_REF连接到CON1屏幕控件上,CREATE OBJECT G_GRID1再创建ALV对象,然后我们给ALV对象注册几个事件,
    1. HANDLE_TOOLBAR这个事件用于给ALV加自定义的工具条按钮。
    2. HANDLE_CLICK用于给ALV点击其中一行后的处理代码段。
    3. HANDLE_COMMAND事件用于接收用户按了自定义按钮后,触发的代码段。


    ABAP中对于事件的使用我分为4步:

    1. 定义事件方法
    2. 指定事件的执行方法代码
    3. 事件变量实例化
    4. 把事件指定到ALV控件中(注册事件)


    *&---------------------------------------------------------------------*
    *&      Module  INIT_CON  OUTPUT
    *&---------------------------------------------------------------------*
    *       text 控件初始化模块
    *----------------------------------------------------------------------*
    MODULE INIT_CON OUTPUT.
    "---------第一个ALV控件-----------------
      IF CON1_REF IS INITIAL.
    
      DATA GS_LAYOUT1 TYPE LVC_S_LAYO.
            GS_LAYOUT1-CWIDTH_OPT = 'X'.
            GS_LAYOUT1-GRID_TITLE = '三包索赔单'.
            GS_LAYOUT1-SEL_MODE = 'B'.
            GS_LAYOUT1-ZEBRA = 'X'.
            DATA GT_FIELDCAT TYPE LVC_T_FCAT.
            DATA GS_FIELDCAT TYPE LVC_S_FCAT.
            GS_FIELDCAT-COL_POS   = 1. GS_FIELDCAT-FIELDNAME = 'BOX'.          GS_FIELDCAT-CHECKBOX = 'X'.    GS_FIELDCAT-HOTSPOT = 'X'.       APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 2. GS_FIELDCAT-FIELDNAME = 'TZNUM'.        GS_FIELDCAT-COLTEXT = '三包索赔单号'.      APPEND GS_FIELDCAT TO GT_FIELDCAT. CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 3. GS_FIELDCAT-FIELDNAME = 'LIFNR'.        GS_FIELDCAT-COLTEXT = '供应商代码'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 4. GS_FIELDCAT-FIELDNAME = 'NAME1'.        GS_FIELDCAT-COLTEXT = '供应商名称'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 5. GS_FIELDCAT-FIELDNAME = 'ERDAT'.        GS_FIELDCAT-COLTEXT = '日期'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 6. GS_FIELDCAT-FIELDNAME = 'EINFR'.        GS_FIELDCAT-COLTEXT = '运费'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
    *        GS_FIELDCAT-COL_POS   = 7. GS_FIELDCAT-FIELDNAME = 'SUMME'.        GS_FIELDCAT-COLTEXT = '总计'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 8. GS_FIELDCAT-FIELDNAME = 'CHUKU'.        GS_FIELDCAT-COLTEXT = '出库'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 9. GS_FIELDCAT-FIELDNAME = 'ISSHEN'.       GS_FIELDCAT-COLTEXT = '审批'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 10. GS_FIELDCAT-FIELDNAME = 'ISDEL'.        GS_FIELDCAT-COLTEXT = '删除'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
        CREATE OBJECT CON1_REF
              EXPORTING
                  CONTAINER_NAME = 'CON1'.
        CREATE OBJECT G_GRID1
              EXPORTING
                  I_PARENT = CON1_REF.
         "4 注册事件句柄,图标的还必须加在这里,不然不行
        CREATE OBJECT EVENT_RECEIVER2.
            SET HANDLER EVENT_RECEIVER2->HANDLE_TOOLBAR FOR G_GRID1.
          "4 注册事件句柄
        CREATE OBJECT EVENT_RECEIVER.
            SET HANDLER EVENT_RECEIVER->HANDLE_CLICK FOR G_GRID1.
          "4 注册事件句柄
        CREATE OBJECT EVENT_RECEIVER3.
            SET HANDLER EVENT_RECEIVER3->HANDLE_COMMAND FOR G_GRID1.
        CALL METHOD G_GRID1->SET_TABLE_FOR_FIRST_DISPLAY
              EXPORTING
                  IS_LAYOUT =  GS_LAYOUT1
                CHANGING
                  IT_OUTTAB = GT_ITAB_HEAD[]
                  IT_FIELDCATALOG = GT_FIELDCAT.
      ENDIF.



    ALV1在非编辑模式单选控制的实现:

    用户单击ALV1中的CKECKBOX时,
    1. 程序首选清空ALV中的全部CKECKBOX
    2. 打上当前用户选的一个CKECKBOX
    3. 刷新ALV




    全部代码:

    *&---------------------------------------------------------------------*
    *& Report  ZMMR0093
    *& 三包索赔单审批及打印程序 潍柴(重庆)汽车
    *&---------------------------------------------------------------------*
    *& james_lx 
    *& 2015.12.10
    *&---------------------------------------------------------------------*
    
    REPORT ZMMR0093.
    
    TYPE-POOLS: ICON.
    
    
    
    TABLES: ZSDT029,ZSDT030.
    DATA GS_ZSDT_LOG029 LIKE ZSDT_LOG029.
    
    
    DATA GT_ZSDT029 LIKE TABLE OF ZSDT029 WITH HEADER LINE.
    DATA GT_ZSDT030 LIKE TABLE OF ZSDT030 WITH HEADER LINE.
    
    
    DATA GT_ITAB        LIKE TABLE OF ZSDS045 WITH HEADER LINE.
    DATA GT_ITAB_HEAD   LIKE TABLE OF ZSDS045 WITH HEADER LINE.
    DATA GS_ITAB_HEAD   LIKE ZSDS045 .
    DATA GT_PRINT       LIKE TABLE OF ZSDS045 WITH HEADER LINE.
    
    
    
    DATA GV_KNUMH LIKE A017-KNUMH.
    
    DATA GV_KPEIN LIKE KONP-KPEIN.
    DATA GV_KBETR LIKE KONP-KBETR.
    
    
    
    DATA  CON1_REF TYPE REF TO CL_GUI_CUSTOM_CONTAINER.
    DATA  CON2_REF TYPE REF TO CL_GUI_CUSTOM_CONTAINER.
    
    DATA  G_GRID1 TYPE REF TO CL_GUI_ALV_GRID.
    DATA  G_GRID2 TYPE REF TO CL_GUI_ALV_GRID.
    
    "-------------------------------------
    "-----------ALV1的HOTSPOT单击事件------------
    "-------------------------------------
    "1 定义ALV1的事件
    
    CLASS LCL_EVENT_RECEIVER DEFINITION.
      PUBLIC SECTION.
        METHODS  HANDLE_CLICK
        FOR EVENT HOTSPOT_CLICK
        OF CL_GUI_ALV_GRID
    
      IMPORTING
            E_ROW_ID
            E_COLUMN_ID
            ES_ROW_NO.
     ENDCLASS.
    
    "2 事件的执行方法
    CLASS LCL_EVENT_RECEIVER IMPLEMENTATION.
      METHOD HANDLE_CLICK.
    
            MESSAGE E_ROW_ID  TYPE 'S'.
    
            "清空原来的X
            LOOP AT GT_ITAB_HEAD INTO GS_ITAB_HEAD.
              GS_ITAB_HEAD-BOX = ''.
              MODIFY GT_ITAB_HEAD FROM GS_ITAB_HEAD.
            ENDLOOP.
    
            "补上当前行的X
            READ TABLE GT_ITAB_HEAD INTO GS_ITAB_HEAD INDEX E_ROW_ID.   "读取当前行
            GS_ITAB_HEAD-BOX = 'X'.
            MODIFY GT_ITAB_HEAD FROM GS_ITAB_HEAD INDEX E_ROW_ID.
    
    
    
            "刷新X
            DATA: LS_STABLE TYPE LVC_S_STBL.
                   LS_STABLE-ROW = 'X'.
                   LS_STABLE-COL = 'X'.
    
    
            CALL METHOD G_GRID1->REFRESH_TABLE_DISPLAY
                   EXPORTING
                     IS_STABLE = LS_STABLE
                     I_SOFT_REFRESH = 'X'.
    
    
      "准备和显示第二个ALV的数据
       DATA GV_TZNUM LIKE  GT_ZSDT030-TZNUM.
    
    
          "得到用户选的一个数据
          LOOP AT GT_ITAB_HEAD INTO GS_ITAB_HEAD.
    
            IF GS_ITAB_HEAD-BOX = 'X'.
    
              GV_TZNUM = GS_ITAB_HEAD-TZNUM.
    
            ENDIF.
    
          ENDLOOP.
    
    
    
          IF GV_TZNUM IS NOT INITIAL.
    
    
    
    
                     SELECT *
                     INTO CORRESPONDING FIELDS OF TABLE GT_PRINT
                     FROM ZSDT029 AS A
                     INNER JOIN ZSDT030 AS B
                     ON A~TZNUM = B~TZNUM
                     WHERE A~TZNUM = GV_TZNUM.
    
    
                     "填充价格数据
    
                      LOOP AT GT_PRINT INTO GT_PRINT.
    
    
    
                                  "物料号补零
                                   CALL FUNCTION 'CONVERSION_EXIT_MATN1_INPUT'
                                    EXPORTING
                                     INPUT              = GT_PRINT-MATNR
                                    IMPORTING
                                     OUTPUT             = GT_PRINT-MATNR.
                                   "供应商补0
                                   CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
                                     EXPORTING
                                       INPUT         = GT_PRINT-LIFNR
                                    IMPORTING
                                       OUTPUT        = GT_PRINT-LIFNR.
    
    
                          SELECT SINGLE KNUMH INTO GV_KNUMH FROM A017 WHERE LIFNR = GT_PRINT-LIFNR AND  MATNR = GT_PRINT-MATNR  AND WERKS = '1001' AND DATBI > GT_PRINT-ERDAT AND DATAB < GT_PRINT-ERDAT.
    
    
    
                          IF SY-SUBRC = 0.
    
    
    
    
    
                                SELECT SINGLE KBETR KPEIN INTO (GV_KBETR , GV_KPEIN) FROM KONP WHERE KNUMH = GV_KNUMH.
    
                                  GT_PRINT-CURR1 = GV_KBETR / GV_KPEIN.
    
    
                                  "物料号去零
                                   CALL FUNCTION 'CONVERSION_EXIT_MATN1_OUTPUT'
                                    EXPORTING
                                     INPUT              = GT_PRINT-MATNR
                                    IMPORTING
                                     OUTPUT             = GT_PRINT-MATNR.
                                   "供应商去0
                                   CALL FUNCTION 'CONVERSION_EXIT_ALPHA_OUTPUT'
                                     EXPORTING
                                       INPUT         = GT_PRINT-LIFNR
                                    IMPORTING
                                       OUTPUT        = GT_PRINT-LIFNR.
    
    
    
                                MODIFY GT_PRINT FROM GT_PRINT.
    
                          ENDIF.
    
    
                      ENDLOOP.
    
    
                        LOOP AT GT_PRINT INTO GT_PRINT.
    
    
                            "求单价(材料单价*1.4 系数)
    
                                "供应商补0
                            CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
                              EXPORTING
                                INPUT         = GT_PRINT-LIFNR
                             IMPORTING
                                OUTPUT        = GT_PRINT-LIFNR.
    
                            SELECT SINGLE NAME4 INTO GT_PRINT-NAME4 FROM LFA1 WHERE LIFNR = GT_PRINT-LIFNR.
    
    
                               "供应商去0
                              CALL FUNCTION 'CONVERSION_EXIT_ALPHA_OUTPUT'
                                EXPORTING
                                  INPUT         = GT_PRINT-LIFNR
                               IMPORTING
                                  OUTPUT        = GT_PRINT-LIFNR.
    
                              IF SY-SUBRC = 0.
    
                                GT_PRINT-CURR2 = GT_PRINT-CURR1 * GT_PRINT-NAME4 .
    
    
                              ENDIF.
    
                          "材料费(单价*数量)
                          GT_PRINT-CURRC =  GT_PRINT-CURR2 * GT_PRINT-ZMENG.
    
    
                          "合计
                          GT_PRINT-SUMME = GT_PRINT-CURRC + GT_PRINT-CURRG + GT_PRINT-CURRJ + GT_PRINT-CURRQ.
    
                          MODIFY GT_PRINT FROM GT_PRINT.
    
    
                        ENDLOOP.
    
    
    
    
                 DATA GS_LAYOUT2 TYPE LVC_S_LAYO.
    
                 GS_LAYOUT2-CWIDTH_OPT = 'X'.
                 GS_LAYOUT2-GRID_TITLE = '详细项目'.
                 GS_LAYOUT2-SEL_MODE = 'B'.
                 GS_LAYOUT2-ZEBRA = 'X'.
    
    
    
                 CALL METHOD G_GRID2->SET_FRONTEND_LAYOUT
                        EXPORTING
                          IS_LAYOUT =  GS_LAYOUT2.
    
    
    
                 CALL METHOD G_GRID2->REFRESH_TABLE_DISPLAY
                        EXPORTING
                          IS_STABLE = LS_STABLE
                          I_SOFT_REFRESH = 'X'.
    
          ENDIF.
    
    
    
      ENDMETHOD.
    ENDCLASS.
    
    
     "3 事件引用变量
        DATA EVENT_RECEIVER TYPE REF TO LCL_EVENT_RECEIVER.
    
    
    
    "-------------------------------------
    "-----------ALV1的加图标事件----------
    "-------------------------------------
    "1 定义ALV1的事件
    
    CLASS LCL_EVENT_RECEIVER2 DEFINITION.
      PUBLIC SECTION.
        METHODS  HANDLE_TOOLBAR
        FOR EVENT TOOLBAR
        OF CL_GUI_ALV_GRID
    
      IMPORTING    E_OBJECT  E_INTERACTIVE.
     ENDCLASS.
    
    
    "2 事件的执行方法
    CLASS LCL_EVENT_RECEIVER2 IMPLEMENTATION.
      METHOD HANDLE_TOOLBAR.
    
        DATA LS_TOOLBAR TYPE STB_BUTTON.
    
        CLEAR LS_TOOLBAR.
        LS_TOOLBAR-BUTN_TYPE = 3.
        APPEND LS_TOOLBAR TO E_OBJECT->MT_TOOLBAR.
    
    
    
        CLEAR LS_TOOLBAR.
        LS_TOOLBAR-FUNCTION = 'MYSHEN'.
        LS_TOOLBAR-ICON = ICON_SET_STATE.
        LS_TOOLBAR-QUICKINFO = '审批确认'.
        LS_TOOLBAR-TEXT = '审批确认'.
        LS_TOOLBAR-DISABLED = ''.
        APPEND LS_TOOLBAR TO E_OBJECT->MT_TOOLBAR.
    
         CLEAR LS_TOOLBAR.
        LS_TOOLBAR-FUNCTION = 'MYSCAN'.
        LS_TOOLBAR-ICON = ICON_STORNO.
        LS_TOOLBAR-QUICKINFO = '取消审批'.
        LS_TOOLBAR-TEXT = '取消审批'.
        LS_TOOLBAR-DISABLED = ''.
        APPEND LS_TOOLBAR TO E_OBJECT->MT_TOOLBAR.
    
        CLEAR LS_TOOLBAR.
        LS_TOOLBAR-FUNCTION = 'MYPRINT'.
        LS_TOOLBAR-ICON = ICON_PRINT.
        LS_TOOLBAR-QUICKINFO = '单据打印'.
        LS_TOOLBAR-TEXT = '单据打印'.
        LS_TOOLBAR-DISABLED = ''.
        APPEND LS_TOOLBAR TO E_OBJECT->MT_TOOLBAR.
    
    
      ENDMETHOD.
    ENDCLASS.
    
    
     "3 事件引用变量
        DATA EVENT_RECEIVER2 TYPE REF TO LCL_EVENT_RECEIVER2.
    
    
    "-------------------------------------
    "-----------ALV1的加按钮响应事件------
    "-------------------------------------
    "1 定义ALV1的事件
    
    CLASS LCL_EVENT_RECEIVER3 DEFINITION.
      PUBLIC SECTION.
        METHODS  HANDLE_COMMAND
        FOR EVENT USER_COMMAND
        OF CL_GUI_ALV_GRID
    
      IMPORTING    E_UCOMM.
     ENDCLASS.
    
    
    "2 事件的执行方法
    CLASS LCL_EVENT_RECEIVER3 IMPLEMENTATION.
      METHOD HANDLE_COMMAND.
    
        CASE E_UCOMM.
    
            WHEN 'MYSHEN'.
              PERFORM SHENFORM.
    
            WHEN 'MYSCAN'.
              PERFORM  SCANCELFORM .
    
            WHEN 'MYPRINT'.
              PERFORM  PPPFORM .
    
          ENDCASE.
    
      ENDMETHOD.
    ENDCLASS.
    
     "3 事件引用变量
        DATA EVENT_RECEIVER3 TYPE REF TO LCL_EVENT_RECEIVER3.
    
    
    
    
    
    
    
    "选择屏幕
    SELECT-OPTIONS GS_TZNUM FOR ZSDT029-TZNUM.  "三包索赔单号
    SELECT-OPTIONS GS_JZNUM	FOR ZSDT030-JZNUM.  "结算单号
    SELECT-OPTIONS GS_LIFNR FOR ZSDT029-LIFNR.  "供应商
    SELECT-OPTIONS GS_ERDAT FOR ZSDT029-ERDAT.  "日期
    SELECT-OPTIONS GS_MATNR	FOR ZSDT030-MATNR.  "配件代码
    
    
    
    
    START-OF-SELECTION.
    
    
    
       SELECT *
       INTO CORRESPONDING FIELDS OF TABLE GT_ITAB
       FROM ZSDT029 AS A
       INNER JOIN ZSDT030 AS B
       ON A~TZNUM = B~TZNUM
       WHERE A~TZNUM IN GS_TZNUM
         AND A~LIFNR IN GS_LIFNR
         AND A~ERDAT IN GS_ERDAT
         AND B~JZNUM IN GS_JZNUM
         AND B~MATNR IN GS_MATNR.
    
    
    
    
    
    "为第一个控件准备数据
    
         LOOP AT GT_ITAB.
    
           MOVE GT_ITAB-TZNUM  TO GT_ITAB_HEAD-TZNUM.
           MOVE GT_ITAB-LIFNR  TO GT_ITAB_HEAD-LIFNR.
           MOVE GT_ITAB-NAME1  TO GT_ITAB_HEAD-NAME1.
           MOVE GT_ITAB-ERDAT  TO GT_ITAB_HEAD-ERDAT.
           MOVE GT_ITAB-EINFR  TO GT_ITAB_HEAD-EINFR.
           MOVE GT_ITAB-SUMME  TO GT_ITAB_HEAD-SUMME.
           MOVE GT_ITAB-CHUKU  TO GT_ITAB_HEAD-CHUKU.
           MOVE GT_ITAB-ISSHEN TO GT_ITAB_HEAD-ISSHEN.
           MOVE GT_ITAB-ISDEL  TO GT_ITAB_HEAD-ISDEL.
    
    
    
           APPEND GT_ITAB_HEAD.
           CLEAR GT_ITAB_HEAD.
    
         ENDLOOP.
    
    SORT GT_ITAB_HEAD.
    DELETE ADJACENT DUPLICATES FROM GT_ITAB_HEAD.
    
    
    
    
    
    
    
    CALL  SCREEN 100.
    
    
    *&---------------------------------------------------------------------*
    *&      Module  STATUS_0100  OUTPUT
    *&---------------------------------------------------------------------*
    *       text
    *----------------------------------------------------------------------*
    MODULE STATUS_0100 OUTPUT.
      SET PF-STATUS 'TOPS'.
    *  SET TITLEBAR 'xxx'.
    
    ENDMODULE.                 " STATUS_0100  OUTPUT
    
    
    
    
    *&---------------------------------------------------------------------*
    *&      Module  INIT_CON  OUTPUT
    *&---------------------------------------------------------------------*
    *       text 控件初始化模块
    *----------------------------------------------------------------------*
    MODULE INIT_CON OUTPUT.
    
    
    "---------第一个ALV控件-----------------
      IF CON1_REF IS INITIAL.
    
    
    
    
    
      DATA GS_LAYOUT1 TYPE LVC_S_LAYO.
    
            GS_LAYOUT1-CWIDTH_OPT = 'X'.
            GS_LAYOUT1-GRID_TITLE = '三包索赔单'.
            GS_LAYOUT1-SEL_MODE = 'B'.
            GS_LAYOUT1-ZEBRA = 'X'.
    
    
            DATA GT_FIELDCAT TYPE LVC_T_FCAT.
            DATA GS_FIELDCAT TYPE LVC_S_FCAT.
    
            GS_FIELDCAT-COL_POS   = 1. GS_FIELDCAT-FIELDNAME = 'BOX'.          GS_FIELDCAT-CHECKBOX = 'X'.    GS_FIELDCAT-HOTSPOT = 'X'.       APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 2. GS_FIELDCAT-FIELDNAME = 'TZNUM'.        GS_FIELDCAT-COLTEXT = '三包索赔单号'.      APPEND GS_FIELDCAT TO GT_FIELDCAT. CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 3. GS_FIELDCAT-FIELDNAME = 'LIFNR'.        GS_FIELDCAT-COLTEXT = '供应商代码'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 4. GS_FIELDCAT-FIELDNAME = 'NAME1'.        GS_FIELDCAT-COLTEXT = '供应商名称'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 5. GS_FIELDCAT-FIELDNAME = 'ERDAT'.        GS_FIELDCAT-COLTEXT = '日期'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 6. GS_FIELDCAT-FIELDNAME = 'EINFR'.        GS_FIELDCAT-COLTEXT = '运费'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
    *        GS_FIELDCAT-COL_POS   = 7. GS_FIELDCAT-FIELDNAME = 'SUMME'.        GS_FIELDCAT-COLTEXT = '总计'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 8. GS_FIELDCAT-FIELDNAME = 'CHUKU'.        GS_FIELDCAT-COLTEXT = '出库'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 9. GS_FIELDCAT-FIELDNAME = 'ISSHEN'.       GS_FIELDCAT-COLTEXT = '审批'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
            GS_FIELDCAT-COL_POS   = 10. GS_FIELDCAT-FIELDNAME = 'ISDEL'.        GS_FIELDCAT-COLTEXT = '删除'.        APPEND GS_FIELDCAT TO GT_FIELDCAT.CLEAR GS_FIELDCAT.
    
    
        CREATE OBJECT CON1_REF
              EXPORTING
                  CONTAINER_NAME = 'CON1'.
    
        CREATE OBJECT G_GRID1
              EXPORTING
                  I_PARENT = CON1_REF.
    
    
         "4 注册事件句柄,图标的还必须加在这里,不然不行
        CREATE OBJECT EVENT_RECEIVER2.
            SET HANDLER EVENT_RECEIVER2->HANDLE_TOOLBAR FOR G_GRID1.
    
          "4 注册事件句柄
        CREATE OBJECT EVENT_RECEIVER.
            SET HANDLER EVENT_RECEIVER->HANDLE_CLICK FOR G_GRID1.
    
    
          "4 注册事件句柄
        CREATE OBJECT EVENT_RECEIVER3.
            SET HANDLER EVENT_RECEIVER3->HANDLE_COMMAND FOR G_GRID1.
    
        CALL METHOD G_GRID1->SET_TABLE_FOR_FIRST_DISPLAY
              EXPORTING
                  IS_LAYOUT =  GS_LAYOUT1
                CHANGING
                  IT_OUTTAB = GT_ITAB_HEAD[]
                  IT_FIELDCATALOG = GT_FIELDCAT.
    
    
    
      ENDIF.
    
    
    
    "---------第二个ALV控件-----------------
      IF CON2_REF IS INITIAL.
    
    
          DATA GS_LAYOUT2 TYPE LVC_S_LAYO.
    
            GS_LAYOUT2-CWIDTH_OPT = 'X'.
            GS_LAYOUT2-GRID_TITLE = '详细项目'.
            GS_LAYOUT2-SEL_MODE = 'B'.
            GS_LAYOUT2-ZEBRA = 'X'.
    
          DATA GT_FIELDCAT2 TYPE LVC_T_FCAT.
          DATA GS_FIELDCAT2 TYPE LVC_S_FCAT.
    
    
            GS_FIELDCAT2-COL_POS   = 2. GS_FIELDCAT2-FIELDNAME = 'JZNUM'.        GS_FIELDCAT2-COLTEXT = '结算单号'.      APPEND GS_FIELDCAT2 TO GT_FIELDCAT2. CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 3. GS_FIELDCAT2-FIELDNAME = 'MAKTX'.        GS_FIELDCAT2-COLTEXT = '配件名称'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 4. GS_FIELDCAT2-FIELDNAME = 'MATNR'.        GS_FIELDCAT2-COLTEXT = '配件代码'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 5. GS_FIELDCAT2-FIELDNAME = 'MEINS'.        GS_FIELDCAT2-COLTEXT = '单位'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 6. GS_FIELDCAT2-FIELDNAME = 'ZMENG'.        GS_FIELDCAT2-COLTEXT = '数量'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 7. GS_FIELDCAT2-FIELDNAME = 'CURR1'.        GS_FIELDCAT2-COLTEXT = '材料单价'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 7. GS_FIELDCAT2-FIELDNAME = 'NAME4'.        GS_FIELDCAT2-COLTEXT = '系数'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 8. GS_FIELDCAT2-FIELDNAME = 'CURR2'.        GS_FIELDCAT2-COLTEXT = '单价(材料单价*1.4) '.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 9. GS_FIELDCAT2-FIELDNAME = 'CURRC'.        GS_FIELDCAT2-COLTEXT = '材料费(单价*数量)'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 10. GS_FIELDCAT2-FIELDNAME = 'CURRG'.        GS_FIELDCAT2-COLTEXT = '工时费'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 10. GS_FIELDCAT2-FIELDNAME = 'CURRJ'.        GS_FIELDCAT2-COLTEXT = '救援费'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 10. GS_FIELDCAT2-FIELDNAME = 'CURRQ'.        GS_FIELDCAT2-COLTEXT = '其它费用'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 10. GS_FIELDCAT2-FIELDNAME = 'SUMME'.        GS_FIELDCAT2-COLTEXT = '合计'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 10. GS_FIELDCAT2-FIELDNAME = 'OTHER'.        GS_FIELDCAT2-COLTEXT = '备注'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
    
            GS_FIELDCAT2-COL_POS   = 10. GS_FIELDCAT2-FIELDNAME = 'TZNUM'.        GS_FIELDCAT2-NO_OUT = 'X'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 10. GS_FIELDCAT2-FIELDNAME = 'LIFNR'.        GS_FIELDCAT2-NO_OUT = 'X'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 10. GS_FIELDCAT2-FIELDNAME = 'NAME1'.        GS_FIELDCAT2-NO_OUT = 'X'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 10. GS_FIELDCAT2-FIELDNAME = 'ERDAT'.        GS_FIELDCAT2-NO_OUT = 'X'.       APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 10. GS_FIELDCAT2-FIELDNAME = 'EINFR'.        GS_FIELDCAT2-NO_OUT = 'X'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 10. GS_FIELDCAT2-FIELDNAME = 'CHUKU'.        GS_FIELDCAT2-NO_OUT = 'X'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 10. GS_FIELDCAT2-FIELDNAME = 'ISSHEN'.        GS_FIELDCAT2-NO_OUT = 'X'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 10. GS_FIELDCAT2-FIELDNAME = 'ISDEL'.        GS_FIELDCAT2-NO_OUT = 'X'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
            GS_FIELDCAT2-COL_POS   = 10. GS_FIELDCAT2-FIELDNAME = 'BOX'.        GS_FIELDCAT2-NO_OUT = 'X'.        APPEND GS_FIELDCAT2 TO GT_FIELDCAT2.CLEAR GS_FIELDCAT2.
    
          CREATE OBJECT CON2_REF
            EXPORTING
              CONTAINER_NAME = 'CON2'.
    
          CREATE OBJECT G_GRID2
              EXPORTING
                  I_PARENT = CON2_REF.
    
    
          CALL METHOD G_GRID2->SET_TABLE_FOR_FIRST_DISPLAY
              EXPORTING
                I_STRUCTURE_NAME = 'ZSDS045'
                 IS_LAYOUT =  GS_LAYOUT2
                CHANGING
                  IT_OUTTAB = GT_PRINT[]
                  IT_FIELDCATALOG = GT_FIELDCAT2.
    
    
     ENDIF.
    
    ENDMODULE.                 " INIT_CON  OUTPUT
    
    
    
    
    
    
    
    
    
    *&---------------------------------------------------------------------*
    *&      Module  USER_COMMAND_0100  INPUT
    *&---------------------------------------------------------------------*
    *       text 这个用户命令,是最上面的 【标准工具条】上的按钮
    *----------------------------------------------------------------------*
    MODULE USER_COMMAND_0100 INPUT.
    
    
     CASE SY-UCOMM.
    
       WHEN 'BACK'.
         LEAVE TO SCREEN 0.
       WHEN 'EXIT'.
         LEAVE PROGRAM.
       WHEN 'SCAN'.
        LEAVE TO SCREEN 0.
       WHEN OTHERS.
    
     ENDCASE.
    
    
    
    ENDMODULE.                 " USER_COMMAND_0100  INPUT
    
    
    
    
    
    
    "------------取消审批的FORM--------------------
    FORM SCANCELFORM .
    
    DATA  GV_ANSWER TYPE C.
    CALL FUNCTION 'POPUP_TO_CONFIRM'
            EXPORTING
              TEXT_QUESTION         = '取消审批?'
              DEFAULT_BUTTON              = '2'
              DISPLAY_CANCEL_BUTTON       = ''
            IMPORTING
              ANSWER                = GV_ANSWER.
    
    IF GV_ANSWER <> 1.
    
      RETURN.
    
    ENDIF.
    
    
    "处理保存到LOG表
    LOOP AT GT_ITAB_HEAD.
    
      IF GT_ITAB_HEAD-BOX = 'X'.
    
          GS_ITAB_HEAD = GT_ITAB_HEAD.
    
    
    
    
                IF GS_ITAB_HEAD-BOX = 'X' AND GS_ITAB_HEAD-ISSHEN = 'X' AND GS_ITAB_HEAD-ISDEL <> 'X' AND GS_ITAB_HEAD-CHUKU <> 'X'.
    
                      GS_ZSDT_LOG029-USRID = SY-UNAME. "用户名
                      GS_ZSDT_LOG029-CRDAT = SY-DATUM. "日期
                      GS_ZSDT_LOG029-ANUZT = SY-UZEIT. "时间
                      CALL FUNCTION 'NUMBER_GET_NEXT'
                         EXPORTING
                           NR_RANGE_NR                   = 'A1'
                           OBJECT                        = 'ZSDFM020'
                        IMPORTING
                           NUMBER                         = GS_ZSDT_LOG029-AUTONUMBER.
                      CALL FUNCTION 'CONVERSION_EXIT_ALPHA_OUTPUT'  "去掉前导零
                        EXPORTING
                          INPUT         = GS_ZSDT_LOG029-AUTONUMBER
                       IMPORTING
                         OUTPUT        =  GS_ZSDT_LOG029-AUTONUMBER.
    
    
    
                      MOVE-CORRESPONDING GS_ITAB_HEAD TO GS_ZSDT_LOG029.
    
    
                      "写业务数据表
                             UPDATE ZSDT029
                             SET  ISSHEN = ''
                             WHERE TZNUM = GS_ITAB_HEAD-TZNUM.
                               COMMIT WORK .
    
    
                      IF SY-SUBRC = 0.
    
    
                              DATA GV_TABIX LIKE SY-TABIX.
    
    
                               "改一下控件的内表X数据
                              LOOP AT GT_ITAB_HEAD.
                                IF GT_ITAB_HEAD-BOX = 'X'.
                                    GV_TABIX = SY-TABIX.
                                ENDIF.
    
                              ENDLOOP.
    
                                 "补上当前行的X
                                READ TABLE GT_ITAB_HEAD INTO GS_ITAB_HEAD INDEX GV_TABIX.   "读取当前行
                                GS_ITAB_HEAD-ISSHEN = ''.
                                MODIFY GT_ITAB_HEAD FROM GS_ITAB_HEAD INDEX GV_TABIX.
    
    
                               "刷新X
                               DATA: LS_STABLE TYPE LVC_S_STBL.
                                      LS_STABLE-ROW = 'X'.
                                      LS_STABLE-COL = 'X'.
    
    
                               CALL METHOD G_GRID1->REFRESH_TABLE_DISPLAY
                                      EXPORTING
                                        IS_STABLE = LS_STABLE
                                        I_SOFT_REFRESH = 'X'.
    
    
    
                             "传给EAI
                              DATA GT_HEADER LIKE TABLE OF ZSDS043 WITH HEADER LINE.
                              DATA GT_RETURN LIKE TABLE OF BAPIRET2 WITH HEADER LINE.
                              DATA RESULT LIKE TREXS_CONNECTION_CHECK_RESULT.
    
                              GT_HEADER-TZNUM = GT_ITAB_HEAD-TZNUM.
                              GT_HEADER-USRID = SY-UNAME.
                              GT_HEADER-CRDAT = SY-DATUM.
                              GT_HEADER-ISSHEN = ''.
                              APPEND GT_HEADER.
    
    
                              CALL FUNCTION 'TREX_RFC_CONNECT_CHECK_LOCAL'
                                EXPORTING
                                  TREX_DESTINATION        = 'SAPEAI'
                                IMPORTING
                                  LOCAL_RESULT            = RESULT
                                EXCEPTIONS
                                  SYSTEM_FAILURE          = 1
                                  COMMUNICATION_FAILURE   = 2
                                  AUTHORITY_NOT_AVAILABLE = 3
                                  SEND_ERROR              = 4
                                  OTHERS                  = 5.
    
                              IF RESULT-ERROR_CODE <> 0."无响应
                                    MESSAGE '连接错误,请检查EAI服务是否注册成功' TYPE 'E'.
                              ELSE.
    
    
                                CALL FUNCTION 'ZSD_IF_FM023' DESTINATION 'SAPJCO'
                                     TABLES
                                      HEADER = GT_HEADER
                                      RETURN = GT_RETURN.
    
    
                                    IF GT_RETURN[] IS NOT INITIAL.
    
                                      READ TABLE GT_RETURN INDEX 1.
    
                                      IF GT_RETURN-TYPE <> 'S'.
                                        GS_ZSDT_LOG029-MESSAGE = ' [EAI接收失败] '.
    
                                      ELSEIF GT_RETURN-TYPE = 'S'.
                                        GS_ZSDT_LOG029-MESSAGE = ' [EAI接收成功] '.
                                      ENDIF.
                                    ENDIF.
    
                                    CLEAR:GT_HEADER,GT_RETURN,GT_HEADER[],GT_RETURN[].
    
                             ENDIF.
    
    
                             GS_ZSDT_LOG029-ISSHEN = ''.      "
                             GS_ZSDT_LOG029-ERPDO = 'X'.      "ERP处理标志
                             GS_ZSDT_LOG029-EDATS = SY-DATUM. "ERP处理日期
                             GS_ZSDT_LOG029-ETIMS = SY-UZEIT. "ERP处理时间
                             GS_ZSDT_LOG029-MESSAGE = GS_ZSDT_LOG029-MESSAGE && '取消审批'.
    
                            "写日志表
                            INSERT ZSDT_LOG029 FROM GS_ZSDT_LOG029.
                              COMMIT WORK .
                            CLEAR  GS_ZSDT_LOG029.
    
    
                      ENDIF.
    
    
                ELSE.
    
                  MESSAGE '操作失败,不满足条件!' TYPE 'E'.
    
                ENDIF.
    
    
    ENDIF.
    
    ENDLOOP.
    
    
    ENDFORM .
    
    
    
    
    
    
    
    "------------SHENFORM的FORM--------------------
    FORM SHENFORM .
    
    DATA  GV_ANSWER TYPE C.
    CALL FUNCTION 'POPUP_TO_CONFIRM'
            EXPORTING
              TEXT_QUESTION         = '确认审批?'
              DEFAULT_BUTTON              = '2'
              DISPLAY_CANCEL_BUTTON       = ''
            IMPORTING
              ANSWER                = GV_ANSWER.
    
    IF GV_ANSWER <> 1.
    
      RETURN.
    
    ENDIF.
    
    
    
    
    
    "处理保存到LOG表
    LOOP AT GT_ITAB_HEAD.
    
      IF GT_ITAB_HEAD-BOX = 'X'.
    
          GS_ITAB_HEAD = GT_ITAB_HEAD.
    
    
    
    
    
                  IF GS_ITAB_HEAD-BOX = 'X' AND GS_ITAB_HEAD-ISSHEN <> 'X' AND GS_ITAB_HEAD-ISDEL <> 'X' AND GS_ITAB_HEAD-CHUKU <> 'X'.
    
                        GS_ZSDT_LOG029-USRID = SY-UNAME. "用户名
                        GS_ZSDT_LOG029-CRDAT = SY-DATUM. "日期
                        GS_ZSDT_LOG029-ANUZT = SY-UZEIT. "时间
                        CALL FUNCTION 'NUMBER_GET_NEXT'
                           EXPORTING
                             NR_RANGE_NR                   = 'A1'
                             OBJECT                        = 'ZSDFM020'
                          IMPORTING
                             NUMBER                         = GS_ZSDT_LOG029-AUTONUMBER.
                        CALL FUNCTION 'CONVERSION_EXIT_ALPHA_OUTPUT'  "去掉前导零
                          EXPORTING
                            INPUT         = GS_ZSDT_LOG029-AUTONUMBER
                         IMPORTING
                           OUTPUT        =  GS_ZSDT_LOG029-AUTONUMBER.
    
    
    
                        MOVE-CORRESPONDING GS_ITAB_HEAD TO GS_ZSDT_LOG029.
    
    
                        "写业务数据表
                               UPDATE ZSDT029
                               SET  ISSHEN = 'X'
                               WHERE TZNUM = GS_ITAB_HEAD-TZNUM.
                                 COMMIT WORK .
    
    
                        IF SY-SUBRC = 0.
    
    
    
    
                              DATA GV_TABIX LIKE SY-TABIX.
    
    
                               "改一下控件的内表X数据
                              LOOP AT GT_ITAB_HEAD.
                                IF GT_ITAB_HEAD-BOX = 'X'.
                                    GV_TABIX = SY-TABIX.
                                ENDIF.
    
                              ENDLOOP.
    
                                 "补上当前行的X
                                READ TABLE GT_ITAB_HEAD INTO GS_ITAB_HEAD INDEX GV_TABIX.   "读取当前行
                                GS_ITAB_HEAD-ISSHEN = 'X'.
                                MODIFY GT_ITAB_HEAD FROM GS_ITAB_HEAD INDEX GV_TABIX.
    
    
                               "刷新X
                               DATA: LS_STABLE TYPE LVC_S_STBL.
                                      LS_STABLE-ROW = 'X'.
                                      LS_STABLE-COL = 'X'.
    
    
                               CALL METHOD G_GRID1->REFRESH_TABLE_DISPLAY
                                      EXPORTING
                                        IS_STABLE = LS_STABLE
                                        I_SOFT_REFRESH = 'X'.
    
    
                               "传给EAI
                                DATA GT_HEADER LIKE TABLE OF ZSDS043 WITH HEADER LINE.
                                DATA GT_RETURN LIKE TABLE OF BAPIRET2 WITH HEADER LINE.
                                DATA RESULT LIKE TREXS_CONNECTION_CHECK_RESULT.
    
                                GT_HEADER-TZNUM = GT_ITAB_HEAD-TZNUM.
                                GT_HEADER-USRID = SY-UNAME.
                                GT_HEADER-CRDAT = SY-DATUM.
                                GT_HEADER-ISSHEN = 'X'.
                                APPEND GT_HEADER.
    
    
                                CALL FUNCTION 'TREX_RFC_CONNECT_CHECK_LOCAL'
                                  EXPORTING
                                    TREX_DESTINATION        = 'SAPEAI'
                                  IMPORTING
                                    LOCAL_RESULT            = RESULT
                                  EXCEPTIONS
                                    SYSTEM_FAILURE          = 1
                                    COMMUNICATION_FAILURE   = 2
                                    AUTHORITY_NOT_AVAILABLE = 3
                                    SEND_ERROR              = 4
                                    OTHERS                  = 5.
    
                                IF RESULT-ERROR_CODE <> 0."无响应
                                      MESSAGE '连接错误,请检查EAI服务是否注册成功' TYPE 'E'.
                                ELSE.
    
    
                                  CALL FUNCTION 'ZSD_IF_FM023' DESTINATION 'SAPJCO'
                                       TABLES
                                        HEADER = GT_HEADER
                                        RETURN = GT_RETURN.
    
    
                                      IF GT_RETURN[] IS NOT INITIAL.
    
                                        READ TABLE GT_RETURN INDEX 1.
    
                                        IF GT_RETURN-TYPE <> 'S'.
                                          GS_ZSDT_LOG029-MESSAGE = ' [EAI接收失败] '.
    
                                        ELSEIF GT_RETURN-TYPE = 'S'.
                                          GS_ZSDT_LOG029-MESSAGE = ' [EAI接收成功] '.
                                        ENDIF.
                                      ENDIF.
    
                                      CLEAR:GT_HEADER,GT_RETURN,GT_HEADER[],GT_RETURN[].
    
                               ENDIF.
    
    
    
    
    
                               GS_ZSDT_LOG029-ISSHEN = 'X'.      "
                               GS_ZSDT_LOG029-ERPDO = 'X'.      "ERP处理标志
                               GS_ZSDT_LOG029-EDATS = SY-DATUM. "ERP处理日期
                               GS_ZSDT_LOG029-ETIMS = SY-UZEIT. "ERP处理时间
                               GS_ZSDT_LOG029-MESSAGE = GS_ZSDT_LOG029-MESSAGE && '确认审批'.
    
                              "写日志表
                              INSERT ZSDT_LOG029 FROM GS_ZSDT_LOG029.
                              COMMIT WORK .
                              CLEAR  GS_ZSDT_LOG029.
    
    
                        ENDIF.
    
    
                        ELSE.
    
                    MESSAGE '操作失败,不满足条件!' TYPE 'E'.
    
                  ENDIF.
    
    ENDIF.
    
    ENDLOOP.
    
    
    
    ENDFORM .
    
    
    
    
    
    
    
    "-------------打印FORM-----------------
    FORM PPPFORM .
    
    
      DATA  GV_FORMNAME TYPE RS38L_FNAM .
    
    
      DATA GS_CONTROL_PARAMS TYPE SSFCTRLOP.
    
          GS_CONTROL_PARAMS-NO_DIALOG = 'X'.
          GS_CONTROL_PARAMS-PREVIEW = 'X'.
    
    
      CALL FUNCTION 'SSF_FUNCTION_MODULE_NAME'
        EXPORTING
          FORMNAME           = 'ZMMR0092'
        IMPORTING
          FM_NAME            = GV_FORMNAME.
    
    
    
    
    
     CALL FUNCTION GV_FORMNAME
         EXPORTING
            CONTROL_PARAMETERS = GS_CONTROL_PARAMS
            USER_SETTINGS      = SPACE
    
    
         TABLES
              GT_TAB         = GT_PRINT[]
         EXCEPTIONS
            FORMATTING_ERROR   = 1
            INTERNAL_ERROR     = 2
            SEND_ERROR         = 3
            USER_CANCELED      = 4
            OTHERS             = 5.
    
    ENDFORM.





    
    展开全文
  • 屏幕 Dynpro

    千次阅读 2017-02-11 09:42:15
    对话屏幕Dynpro(SE51) 屏幕元素 屏幕属性 l 屏幕序号(Screen number)。四个数字组成的序列号,用于在程序中确定屏幕,该序号在同一个ABAP程序内部是唯一的。 l 屏幕类型(Screen type)。ABAP中的...
  • 设置树莓派屏幕常亮,禁止树莓派屏幕休眠

    千次阅读 多人点赞 2020-07-19 20:35:33
    2、 Raspbian系统使用的是lightdm桌面显示管理器,可以设置xservice桌面交互显示来达到屏幕常亮的目的。 3、修改桌面配置文件lightdm.conf sudo nano /etc/lightdm/lightdm.conf 找到[Seat:*]这一
  • 远程屏幕监控系统

    千次阅读 2018-05-12 20:41:13
    完整代码以及本文的word都在放在了Github上,你可以下载或使用它:远程屏幕监控系统项目地址,如果喜欢的话,就去点个Star吧 摘要 远程屏幕监控系统在生活中是很常见的,学校机房的机房管理系统、PC版QQ的远程...
  • 今天还是给大家带来自定义控件的编写,自定义一个ListView的左右滑动删除Item的效果,这个效果之前已经实现过了,有兴趣的可以看下Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果,之前使用的是滑动类...
  • [摘要:xshell正在输进敕令时,若是敲错字母了的时间,念经过按退键删除敲错的字母,却正在屏幕表现出了“^H”,退不可,再按删除键,却表现出“^[[3~”,怎样着便是删除没有了输错的字母。 建] ...
  • 一,VMware中Linux虚拟机屏幕分辨率调整之前安装修改Linux分辨率命令行 在VMware中安装Linux虚拟机后,屏幕分辨率通常默认设置为800x600,并且不能通过“屏幕分辨率首选项”窗口(系统->首选项->屏幕分辨率)进行...
  • [摘要:xshell正在输进敕令时,若是敲错字母了的时间,念经过按退键删除敲错的字母,却正在屏幕表现出了“^H”,退不可,再按删除键,却表现出“^[[3~”,怎样着便是删除没有了输错的字母。 建...
  • 对话屏幕Dynpro(SE51) 屏幕元素 屏幕属性 PAI事件的触发、屏幕元素Function Code设置 屏幕流逻辑Screen Flow Logic 对话屏幕中的字段命名大小写问题 示例:屏幕元素自动参考数据词典(或程序)中的表或结构...
  • Fliqlo屏幕保护程序 双击“Fliqlo Screensaver”文件夹中标有“Fliqlo.exe”的图标。 缺省安装即可。 时钟屏保1.5.1 右键单击名为“Fliqlo”的文件。scr”,选择“安装”使其成为默认屏保,然后“屏保设置”面板将...
  • 指尖初体验之主屏幕操作

    千次阅读 2012-10-26 10:26:08
    激活完成了,你手中的iPad是屏幕锁定状态,拖动滑块便可解除锁定而进入iPad的主屏幕。 主屏幕屏幕是 iPad 的起始页面,你可以在此找到你的全部应用程序和文件夹。点按主屏幕按钮就可在此切换应用程序,你还可以...
  • 我主要是运用在用户在锁屏状态下收到新的通知时,同时能够点亮屏幕。一个工具类package com.example.testone;import android.content.Context; import android.os.PowerManager; import android.os.SystemClock;...
  • 迪文屏幕学习笔记零:迪文屏幕的学习和开发

    千次阅读 多人点赞 2019-10-27 21:38:04
    迪文屏幕的学习和开发 一、前言   最近需要做一个关于迪文屏幕的项目,通过这几天的学习,对其开发方法有了大致的了解,但是涉及到 OS 部分还没有完成,现在即将离开,因此项目暂时中止,以后有机会再继续了解,...
  • 关于屏幕分辨率适配的教程

    千次阅读 2016-09-30 11:22:44
    对于屏幕分辨率 如果你现在问我px/dpi...我可能还会头晕,但是,不代表不可以做屏幕适配!!! 关于屏幕适配,你只需要知道,能够让一个控件在不同分辨率下显示的效果一致(或者差不多) ,适配就OK了 举个栗子 一个button 在...
  • 对话屏幕Dynpro(se51)

    千次阅读 2015-12-14 19:26:34
    对话屏幕Dynpro(SE51) 屏幕元素 屏幕属性 l 屏幕序号(Screen number)。四个数字组成的序列号,用于在程序中确定屏幕,该序号在同一个ABAP程序内部是唯一的。 l 屏幕类型(Screen type)。ABAP中的屏幕类型...
  • 保持Android手机屏幕长亮

    千次阅读 2013-07-10 16:22:35
    我们知道手机为了省电设计,在一段时间没有操作的时候屏幕的灯会自动关闭,但是很多时候我们需要让手机屏幕保持亮着,例如我们使用手机看电影或者录像的时候,都需要屏幕常亮,因此这里ataaw.com归纳下在Android手机...
  • windows 快捷键关闭屏幕

    千次阅读 2019-02-27 16:06:48
    台式机没有Fn+F7关闭屏幕的快捷键,这里小bo找了一款相对好用的小工具,设置快捷方式/设置快捷键,并且“启动后即执行功能”,即可实现快捷键关闭屏幕的功能了! 下载地址:...
  • SAP 屏幕逻辑流

    千次阅读 2013-05-17 11:22:35
    屏幕中有四个主要的逻辑流 (PBO,PAI POH,POV) PROCESS BEFORE OUTPUT. ... 该模块监听用户操作时间 PROCESS ON HELP-REQUEST.  FIELD FIELD_NAME MODULE HELP_MODULE.  当用户查看帮助信息时
  • 关注工种号:潮软件 软件介绍 ...一个简单直观的时间轴使编辑视频更加容易。组合或者分割剪辑,修剪,加快或者减慢。直接在视频编辑器里面预览。 为视频添加专业的视频编辑器特效。添加高亮,动画,标...
  • Android RecyclerView 使用完全解析 体验艺术般的控件

    万次阅读 多人点赞 2015-04-16 09:07:16
    RecyclerView出现已经有一段时间了,相信大家肯定不陌生了,大家可以通过导入support-v7对其进行使用。 据官方的介绍,该控件用于在有限的窗口中展示大量数据集,其实这样功能的控件我们并不陌生,例如:ListView、...
  • 远程控制编写之屏幕传输 MFC实现 屏幕截图 发送bmp数据 显示bmp图像: 一 : 首先要了解bmp图像的结构 详情请看我转载的一篇文章http://blog.csdn.net/hnust_xiehonghao/article/details/37656281 二: 被控端的代码...
  • (旧)运行时间分析工具:se30 (新)运行时间分析工具:SAT 1.0 简要说明 Se30运行时分析工具,提供了详细的程序运行时环境的数据,对性能调优有很大的帮助。我们可以通过SE30分析事务代码(tcode)程序(se38)...
  • 关于 Android 4.4 系统屏幕旋转调研

    千次阅读 2015-04-08 23:53:46
    本文档是在全志A33平台 Android 系统中,关于屏幕旋转方面的技术调研。
  • Win7 自制关闭屏幕快捷键

    千次阅读 2018-11-10 10:54:26
    Win7 自制关闭屏幕快捷键
  • surface pro触摸屏幕出现异常

    千次阅读 2019-04-01 18:05:36
    我的surface pro前一段时间装完虚拟机之后忽然屏幕的一个宽条无法用触控笔或者手指书写,进行了很多尝试。 以下是我各种尝试的合集 首先查看系统有没有更新到最新版本 ,我当时正好没有更新,但事实告诉我不是更新...
  • cron读取一个或多个配置文件,这些配置文件中包含了命令行及其调用时间。 cron的配置文件称为“crontab”,是“cron table”的简写。 第一、服务操作  cron是一个linux下 的定时执行工具,可以在无需人工干预的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 214,720
精华内容 85,888
关键字:

如何删除屏幕使用时间