美文网首页
RemoteView

RemoteView

作者: 马也程序猴 | 来源:发表于2021-06-22 22:24 被阅读0次

    常驻通知栏

    Notification

    //使用Notification,需要注意在android8.0以上的系统中,需要定义channel,否则无法显示通知
    mBuilder = new NotificationCompat.Builder(this, CHANNEL_TOOLS);
    mBuilder.setSmallIcon(R.drawable.ic_notification); // 设置顶部图标(状态栏)
    
    //需要实现自定义的布局,需要实现RemoteView,通过setContent()方法设置
    mBuilder.setContent(remoteViews);
    
    注意点:
    1. 布局尽量不要限制死高度,在不同的Room下高度过大可能导致View超出通知框范围
    2. 布局背景颜色需要考虑,尽量使用透明背景色,同时布局内其他组件也尽量保证在父布局透明时能够保持正常视图
    3. 不能保证透明时较好的效果,则需要统一定死背景颜色,牺牲一定的room兼容(某些room获取通知栏颜色不准,会影响动态设置背景色)
    

    RemoteView

    自定义通知栏中,需要自定义通知栏的视图时,需要使用RemoteView定义视图,代码示例

    //定义RemoteView视图
    RemoteView remoteViews = new RemoteViews(getPackageName(), R.layout.layout_tools_unit_normal_white);
    
    //需要注意,在RemoteView中使用的空间有比较严格的限制,仅支持有限的几种控件
    //支持控件:
    
    //布局
    FrameLayout,LinearLayout,RelativeLayout,GridLayout
    
    //控件
    AnalogClock,Button,Chronometer,ImageButton,ImageView,ProgressBar,TextView,ViewFlipper,ListView,GridView,StackView,AdapterViewFlipper,ViewStub
    
    注意点
    1. 在RemoteView中自定义控件是莫得用的
    2. 在RemoteView中没法直接拿到子View对象(可以通过方法操控)
    
    

    RemoteView内的控件无法直接通过findViewById来获取,所以控制RemoteView中的组件需要通过提供的方法:

    例如:
    setTextViewText(int viewId, CharSequence text)
    setImageViewResourse(int viewId, int resId)
    setTextColor(int viewId, int color)
    
    //实际上这一些方法的实现机制是通过反射完成的,所有RemoteView的子组件都通过RemoteView调用提供的方法来操作
    
    

    常驻效果

    //常驻效果可以通过这行代码实现
    mBuilder.setOngoing(true);
    
    

    小部件

    小部件是可以单独在桌面显示的内容,本质上AppWidget实现的是一个广播(BroadCastReceiver),生成一个小部件会通知我们对AppWidget的定义,然后生成相应的布局以及内容

    定义小部件主体

    实现小部件:继承AppWidgetProvider
    
    public class MyAgentWidget extends AppWidgetProvider {
        
        /*
         * 核心方法,在更新的时候调用
         */
        public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds){
            //appWidgetManager:主要用来调用updataAppWidget(int appwidgetId, RemoteView view)
            //这一方法用来替换刷新appwidgetId对应的小部件的布局显示,通过RemoteView控制布局内容
            //AppWidget装载内容同样使用的是RemoteView,所以RemoteView相关的限制在小部件上也一样存在
    
            //appWidgetIds:小部件定义完成以后,用户可以在桌面生成多个相同的小部件,所以一个小部件update()中对应的id会是数组类型的数据
    
        }
        
        
        public void onEnable(Context context) {
            //小部件首次添加到桌面时调用
        }
        
        public void onDisable(Context context) {
            //小部件移除桌面时调用
        }
    }
    
    

    AppWidgetManager的实例可以通过getInstance()来获取,在非Widget定义部分的代码也可以对小部件的内容进行修改

    //将RemoteView设置给指定的小部件替换为新的布局样式
    AppWidgetManager.getInstance().updateAppWidget(new ComponentName(Context, 小部件.class), RemoteView)
    

    小部件注册

    小部件本体是一个BroadCastReceiver,那么对应的在AndroidMainfest里要进行注册

    <receiver android:name=".appwidget.MyAppWidget">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data
            android:name="android.appwidget.provider"
            <!-- resource指向的xml文件是对Widget的一些基本定义 -->
            android:resource="@xml/msg_widget_mine" />
    </receiver>
    

    小部件定义

    在xml文件夹下,

    <?xml version="1.0" encoding="utf-8"?>
    <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
        android:initialKeyguardLayout="@layout/agent_tool_widget"   <!-- 初始定义锁屏页面中布局 -->
        android:initialLayout="@layout/agent_tool_widget"           <!-- 初始定义桌面中布局 -->
        
        android:minHeight="40dp"                                    <!-- 布局最小高度 -->   
        android:minWidth="250dp"                                    <!-- 布局最小宽度 -->
        
        android:previewImage="@mipmap/ic_tools"                     <!-- 在选择小部件时展示的图片 -->
        android:updatePeriodMillis="86400000"                       <!-- 更新时间毫秒值 -->
        android:widgetCategory="home_screen"></appwidget-provider>  <!-- 相当于一个类别小部件的标识 --> 
    
    需要注意的是:通常定义下,桌面中的一格,宽高都是40dp,但在不同的room下表现都会有差别(部分系统会在边界添加padding),所以整体父布局尽量避免使用padding,保持和桌面应用的入口相似。
    只占单格的小部件样式为了更好的适配,最好只用一张图片展示
    
    
    

    快捷方式

    快捷方式的实现和小部件原理相似,同样是发送广播生成;广播发送后由系统接收,之后根据广播中包含的内容生成快捷方式;

    权限申请

    <!-- 快捷方式生成 -->
    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
    <!-- 快捷方式移除 -->
    <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
    <!-- 快捷方式读取信息 -->
    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.android.launcher2.permission.READ_SETTINGS" />
    <uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" />
    

    生成快捷方式

    ShortcutInfoCompat info = new ShortcutInfoCompat(Context context, String title)
        .setIcon(快捷方式图标(Bitmap,IconCompat,Drawable))
        .setShortLabel(String title)
        .setIntent(点击快捷方式发出的Intent)
        .build();
        
    //生成制定快捷方式   
    PendingIntent shortcutCallbackIntent = PendingIntent.getBroadCast(Context context, int type:快捷方式的唯一标识, Intent intent, PendingIntent.FLAG_UPDATE_CURRENT)
    ShortcutManagerCompat.requestPinShortcut(Context context, ShortcutInfoCompat info, IntentSender intentSender)    
    
    

    快捷方式点击

    Intnet intent = new Intent(Context context, Class clazz);
    intent.setAction(Intent.ACTION_VIEW);   //必须设置项,缺失会导致崩溃
    

    在首页点击快捷方式后将会直接根据Intent的内容进行相应的跳转,此处的Intent可以设置FLAG来控制Activity的启动模式


    关于PendingIntent的点击效果

    在RemoteView中要申明点击事件需要借助PendingIntent来完成,但是有非常重要的一点在于,PendingIntent中申明的Flag是没有效果的,也就是说需要跳转到首页之类的页面时,在Intent中指定的启动模式是不会起到作用的;
    如果原先的首页是standard模式(一般都设置为这个模式),那么就会在跳转是创建一个新的首页(emm....),而修改首页的launchMode也并不可取,会影响到切置后台再从图标进入时的逻辑;

    对于RemoteView的点击目标最好不要直接跳转到首页,如果有必须跳转的情况,这时就需要一个中转页面来辅助跳转,因为PendingIntent无法传递launchMode,所以需要先跳转至中转页,再由中转页通过Intent来定义launchMode,通过这种方式可以做到正确的跳转

    相关文章

      网友评论

          本文标题:RemoteView

          本文链接:https://www.haomeiwen.com/subject/cfgkzctx.html