小组件简单实现刷新

在项目中右键创建widget后,我们需要一个service控制刷新。

效果图:

class WidgetsService : Service() {

    companion object {
        const val TAG = "WidgetsServiceTAG"

        fun start(ids: String, context: Context) {
            val intent = Intent(context, WidgetsService::class.java)
            intent.putExtra("widgetIds", ids)
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                Log.e(TAG, "start: yyyyy")
                context.startForegroundService(intent)
            } else {
                Log.e(TAG, "start: nnnnn")
                context.startService(intent)
            }
        }
    }

    /**
     * 1是竖屏2是横屏
     */
    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        Log.d(TAG, "onConfigurationChanged: ${newConfig.orientation}")
//        if (SpUtils.getBoolean("suspension_switch", false)) {
//            SuspensionFragment.newInstance().resetDisplay(newConfig.orientation)
//        }

    }

    private var widgetId: String? = null

    private var timer: Timer? = null
    override fun onCreate() {
        super.onCreate()

        timer = Timer()
        timer?.schedule(object : TimerTask() {
            override fun run() {
                updateWidgets()
            }
        }, 0, 1000)
        startNotificationForeground()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.e(TAG, "onStartCommand: ${intent?.getStringExtra("widgetIds")}")
        widgetId = intent?.getStringExtra("widgetIds")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onBind(intent: Intent?): IBinder? = null


    /**
     * @describe: 前台通知
     * @date: 2022/7/5 09:47
     **/
    private fun startNotificationForeground() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channelId = "WidgetService"
            val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
            val channel = NotificationChannel(channelId, "主服务", NotificationManager.IMPORTANCE_HIGH)
            channel.enableLights(false) //设置提示灯
            channel.lightColor = Color.RED //设置提示灯颜色
            channel.setShowBadge(true) //显示logo
            channel.description = "widgets_daycare" //设置描述
            channel.lockscreenVisibility =
                Notification.VISIBILITY_SECRET //设置锁屏可见 VISIBILITY_PUBLIC=可见
            manager.createNotificationChannel(channel)
            val notification: Notification = Notification.Builder(this)
                .setChannelId(channelId)
                .setAutoCancel(false)
                .setContentText("建议保留该通知,以保证小组件功能正常使用~") //内容
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
            //小图标一定需要设置,否则会报错(如果不设置它启动服务前台化不会报错,但是你会发现这个通知不会启动),如果是普通通知,不设置必然报错
//                .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.ic_open_page))
                .build()

            startForeground(
                333,
                notification
            ) //服务前台化只能使用startForeground()方法,不能使用 notificationManager.notify(1,notification); 这个只是启动通知使用的,使用这个方法你只需要等待几秒就会发现报错了


        }
    }


    /**
     * @describe: 更新组件
     * @date: 2022/7/5 11:04
     **/
    private fun updateWidgets() {
        GlobalScope.launch(Dispatchers.Default) {
            try {
                updateColorSmallWidget()
                updateFlipWidget()
            } catch (ex: Exception) {
            }
        }
    }

    /**
     * @describe: 更新彩色180*180组件
     * @date: 2022/7/6 15:44
     **/
    private fun updateColorSmallWidget() {
        val appWidgetManager = getSystemService(Context.APPWIDGET_SERVICE) as AppWidgetManager
        val srcId = loadIconPref(this)
        val contentView = LayoutInflater.from(this)
            .inflate(R.layout.activity_contracted_widget, null)
        val widgetInfo = SuspensionUtil().getWidgetInfo()?.get(0)
        contentView.findViewById<TextClock>(R.id.tv_hour).format12Hour = "hh:mm"
        contentView.findViewById<TextClock>(R.id.tv_hour).format24Hour = "hh:mm"
        contentView.findViewById<TextClock>(R.id.tv_week).format12Hour = "MM月dd日 EEEE"
        contentView.findViewById<TextClock>(R.id.tv_week).format24Hour = "MM月dd日 EEEE"
        contentView.findViewById<TextView>(R.id.tv_lunar).text = ChinaDate.getCurrentLunarDate3()
        widgetInfo?.textColor?.let {
            contentView.findViewById<TextClock>(R.id.tv_hour).setTextColor(
                it
            )
        }
        widgetInfo?.textColor?.let {
            contentView.findViewById<TextClock>(R.id.tv_week).setTextColor(
                it
            )
        }
        widgetInfo?.textColor?.let {
            contentView.findViewById<TextView>(R.id.tv_lunar).setTextColor(
                it
            )
        }

        if (widgetInfo?.aboardColor != null && widgetInfo?.aboardColor != -1) {
            val drawable = SuspensionUtil().gradientDrawable(this, widgetInfo?.aboardColor)
            contentView.findViewById<ImageView>(R.id.image_aboard).setImageDrawable(drawable)
        }

        contentView.findViewById<RoundedImageView>(R.id.image_view).setImageResource(srcId)
        /**
         * 设置显示的组件尺寸
         */
        val view = layoutView(
            contentView,
            DpOrPxUtils.dip2px(this, 180f),
            DpOrPxUtils.dip2px(this, 180f)
        )

        val contentBitmap = createContentBitmap(view)

        // Construct the RemoteViews object
        val views = RemoteViews(this.packageName, R.layout.new_app_widget)
        views.setImageViewBitmap(R.id.iv_bg, contentBitmap)

        // Instruct the widget manager to update the widget
        val componentName = ComponentName(
            App.instance,
            ContractedWidget::class.java
        )
        appWidgetManager.updateAppWidget(componentName, views)
    }

    /**
     * @describe: 更新彩色180*180组件
     * @date: 2022/7/6 15:44
     **/
    private fun updateFlipWidget() {
        val appWidgetManager = getSystemService(Context.APPWIDGET_SERVICE) as AppWidgetManager
        val srcId = loadIconPref(this)
        val contentView = LayoutInflater.from(this)
            .inflate(R.layout.activity_flip_widget, null)
        val widgetInfo = SuspensionUtil().getWidgetInfo()?.get(0)
        contentView.findViewById<TextClock>(R.id.tv_week).format12Hour = "MM月dd日 EEEE"
        contentView.findViewById<TextClock>(R.id.tv_week).format24Hour = "MM月dd日 EEEE"
        widgetInfo?.textColor?.let {
            contentView.findViewById<TextClock>(R.id.tv_week).setTextColor(
                it
            )
        }
        widgetInfo?.textColor?.let {
            contentView.findViewById<FlipLayout>(R.id.bit_flip_hour).setFLipTextColor(it)
            contentView.findViewById<FlipLayout>(R.id.bit_flip_minute).setFLipTextColor(it)
            contentView.findViewById<TextView>(R.id.dian1).setTextColor(it)
        }

        val tvCurrentHourTime: FlipLayout = contentView.findViewById<FlipLayout>(R.id.bit_flip_hour)
        val tvCurrentMinTime: FlipLayout =
            contentView.findViewById<FlipLayout>(R.id.bit_flip_minute)

        if (android.text.format.DateFormat.is24HourFormat(this)) {
            tvCurrentHourTime.flip(DateUtils.getHour(), 24, TimeTAG.hour)
        } else {
            tvCurrentHourTime.flip(DateUtils.getHour(), 12, TimeTAG.hour)
        }
        tvCurrentMinTime.flip(DateUtils.getMinute(), 60, TimeTAG.min)

        if (widgetInfo?.aboardColor != null && widgetInfo?.aboardColor != -1) {
            val drawable = SuspensionUtil().gradientDrawable(this, widgetInfo?.aboardColor)
            contentView.findViewById<ImageView>(R.id.image_aboard).setImageDrawable(drawable)
        }

        contentView.findViewById<RoundedImageView>(R.id.image_view).setImageResource(srcId)
        /**
         * 设置显示的组件尺寸
         */
        val view = layoutView(
            contentView,
            DpOrPxUtils.dip2px(this, 180f),
            DpOrPxUtils.dip2px(this, 180f)
        )

        val contentBitmap = createContentBitmap(view)

        // Construct the RemoteViews object
        val views = RemoteViews(this.packageName, R.layout.flip_widget)
        views.setImageViewBitmap(R.id.iv_flip_bg, contentBitmap)

        // Instruct the widget manager to update the widget
        val componentName = ComponentName(
            App.instance,
            FlipWidget::class.java
        )
        appWidgetManager.updateAppWidget(componentName, views)
    }


    /**
     *  渲染view
     */
    private fun layoutView(view: View, widgetWidth: Int, widgetHeight: Int): View {
        val metric = DisplayMetrics()
        val windowManager =
            view.context.applicationContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager
        windowManager.defaultDisplay.getRealMetrics(metric)
        val measuredW = View.MeasureSpec.makeMeasureSpec(widgetWidth, View.MeasureSpec.AT_MOST)
        val measuredH = View.MeasureSpec.makeMeasureSpec(widgetHeight, View.MeasureSpec.AT_MOST)
        view.measure(measuredW, measuredH)
        view.layout(0, 0, widgetWidth, widgetHeight)
        return view
    }

    /**
     * 设置点击按钮对应的PendingIntent
     * @param context
     * @param buttonShowId
     * @return
     */
    private fun getPendingIntent(
        context: Context,
        buttonShowId: String,
        cls: Class<*>
    ): PendingIntent {
        val intent = Intent()
        intent.setClass(context, cls)
        intent.action = Intent.CATEGORY_ALTERNATIVE
        intent.putExtra("receive", buttonShowId)
        return PendingIntent.getBroadcast(context, 0, intent, 0)
    }

    override fun onDestroy() {
        super.onDestroy()
        if (timer != null) {
            timer?.cancel()
            timer = null
        }
        Log.d(TAG, "onDestroy: 1112222")
    }
}

private const val PREFS_NAME = "com.example.appwidget.AppWidget"
private const val PREF_ICON_KEY = "appwidget_icon"
internal fun loadIconPref(context: Context): Int {
    val prefs = context.getSharedPreferences(PREFS_NAME, 0)
    val widgetInfo = SuspensionUtil().getWidgetInfo()

    return prefs.getInt(
        PREF_ICON_KEY,
        CommonUtil.getResourceId(context, widgetInfo?.get(0)?.bgName)
    )
}

/**
 * 创建内容bitmap
 */
internal fun createContentBitmap(view: View): Bitmap {
    //创建画布bitmap
    val bitmap =
        Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
    //val bitmap =
    //            Bitmap.createBitmap(DpOrPxUtils.dip2px(this,180f),DpOrPxUtils.dip2px(this,180f), Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    //使控件可以进行缓存
    view.isDrawingCacheEnabled = true
    //复制获取的 Bitmap
    val drawingCache = Bitmap.createBitmap(view.drawingCache)
    //关闭视图的缓存
    view.isDrawingCacheEnabled = false
    //画内容
    canvas.drawBitmap(drawingCache, 0f, 0f, null)
    return bitmap
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
微信小程序提供了下拉刷新组件`<scroll-view>`,可以在其中嵌套页面内容,实现下拉刷新的效果。 以下是一个示例代码: ```xml <scroll-view bindscrolltoupper="onPullDownRefresh" scroll-y="true" style="height: 100%;"> <!-- 页面内容 --> <!-- ... --> <!-- 下拉刷新区域 --> <view slot="down"> <view wx:if="{{refreshing}}"> <text>加载中...</text> </view> <view wx:else> <text>下拉刷新</text> </view> </view> </scroll-view> ``` 在上述代码中,我们使用`<scroll-view>`组件来作为页面的容器,通过设置`scroll-y="true"`来开启纵向滚动。 在`<scroll-view>`组件中,我们使用了`slot="down"`来指定下拉刷新区域。在这个区域内,我们可以根据状态来展示不同的内容,例如加载中的提示或者下拉刷新的提示。 同时,我们通过绑定`bindscrolltoupper`事件来监听用户下拉页面的操作。当用户下拉页面时,触发该事件,并执行对应的事件处理函数。 以下是一个简单的示例代码: ```javascript Page({ data: { refreshing: false }, onPullDownRefresh() { // 开始下拉刷新 this.setData({ refreshing: true }); // 在这里编写下拉刷新的逻辑,如请求新数据、更新页面等 // 例如: // 发起请求获取新数据 wx.request({ url: 'https://api.example.com/data', success: (res) => { // 更新页面数据 this.setData({ data: res.data, refreshing: false }); // 停止下拉刷新动画 wx.stopPullDownRefresh(); }, fail: (error) => { console.log(error); // 停止下拉刷新动画 wx.stopPullDownRefresh(); } }); } }); ``` 在上述代码中,`onPullDownRefresh`事件处理函数中可以编写下拉刷新的逻辑。首先设置`refreshing`为`true`,表示开始下拉刷新的状态。然后可以发起请求获取新的数据,并在请求成功后更新页面数据,最后使用`wx.stopPullDownRefresh()`方法停止下拉刷新动画,并将`refreshing`设置为`false`,表示下拉刷新完成。 希望对你有帮助!如有更多问题,请继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_41620230

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值