widget_widgets - CSDN
  • Widget组件及设计介绍

    2011-08-04 23:47:06
    以下仅代表个人的想法,仅供大家参考,...我们可以看到Widget是一种展示在手机主屏的一种快速浏览的一个插件。 Widget的应用很广,可以应用到WEB、桌面和手机端。例如操作系统上的时钟、天气、资讯的小插件都属于Widge
       以下仅代表个人的想法,仅供大家参考,如有不对之处请大家指出,这也是我调研的结果,加以总结:
    

    我们可以看到Widget是一种展示在手机主屏的一种快速浏览的一个插件。

    Widget的应用很广,可以应用到WEB、桌面和手机端。例如操作系统上的时钟、天气、资讯的小插件都属于Widget。

    现在的智能手机就相当于一智能电脑,其桌面也可以填充格式各样的Widget,这里Android SDK1.5以上就提供了对Widget非常好的支持。

    Widget有几大特点

    1、身材微:一般的它们都比较小,在终端上嵌入十分的方便,运行快速。

    2、形式多:Widget的展现形式多,可以自定义样式,如幻灯秀、视频、地图、新闻、小游戏等..

    3、个性化:可以在桌面上展示个性化的服务,根据自己的需求来排列、显示。也可以设置一些widget的显示形式和更新频率。

    4、连动性:对于一个主应用程序,其相当于是一个桌面窗口一样和主程序在实时连动,可以显示一些主要的信息内容,在不必要时不需要进入主程序。

    Android上主流的一些APP Widget应用:

    其中包括新浪微博、人人网、小米读书、墨迹天气、开关控件、QQ、日期等一些的应用。

    Android上是怎么实现APP Widget的?

       实际上在Android发开包中,它把所有的一些控件包括button、txtarea、menu等等都叫做Widget,而我们实际上说的Widget 是属于 APP Widget(APPLIACTION),这个只要大家了解一下就可以了。     

    Widget的实现对于Android 上并不是什么难事,在Android SDK1.5版本的时候就已经推出了Widget的功能,并且Android手机也自带了许多插件,虽然有些并不是很个性,美观,但是我们还可以选择很多第三方开发的Widget来个性化自己的桌面。

    Android上的APP  Widget设计

    首先设计尺寸规则有一个公示:最小尺寸(dip)=(格子数*74)-2

    所谓的格子数就是指.主屏分为4X4的格子根据自己设计占的格子数来创建的。

    标准Widget剖析

    典型的AndroidWidget主要有三个组成部分:一个限位框,一个框架,还有Widget的图形控件以及其它元素.设计周全的Widget会在限位框边缘&框架之间,及框架内边缘&Widget的控件之间都保留一些内填充(内补白).Widget的外观被设计得与主屏幕的其它Widget相匹配,并以主屏幕的其它元素为依据对齐;它们亦使用标准的阴影效果.此文档说明了所有的相关细节.

                     标准Widget尺寸(纵向)

                标准Widget尺寸(横向)

    设计一个Widget

    ◆为你的Widget选择限位框尺寸.

    最有效的Widget会以最小型的尺寸来显示程序有用或及时的数据.用户会衡量Widget的有用性或它所占的屏幕空间,因此越小越好.

    所有Widget必须符合限位框的六种尺寸之一,或者更好的是,或更好的是在一对纵向和横向的方位尺寸里,这样在用户切换屏幕方向时,你的Widget看起来也会更舒适.

    标准Widget尺寸以图例说明了六种Widget尺寸的限位规格(三种纵向三种横向).

    ◆选择匹配的框架.

    标准Widget框架以图例说明了六种Widget尺寸的标准框架,你可以下载此链接的副本备用.你的Widget并非都必须使用这些框架,但若你用了,你的Widget可能与其它Widget看起来更一致.

     

    ◆对图形应用标准阴影效果.

    此外,你并非必须使用此效果,但标准Widget阴影说明了标准Widget使用的Photoshop设置.

    ◆若你的Widget包含按钮,需绘制按钮的三种状态(默认,按下,被选中).

    你可以下载一个音乐Widget播放按钮的Photoshop文件(包含三种状态) ,用来分析三种标准按钮效果的Photoshop设置.

    标准Widget尺寸

    这里有六种基于4 x 4 (纵向)或 4 x 4 (横向)单元的主屏幕网格的标准Widget尺寸.这些规格为六种标准Widget尺寸的限位框.这些尺度是六种标准Widget尺寸限位框.典型Widget的内容并不绘制这些尺度的边缘线,但在限位框里填充一个框架正如设计一个Widget所说到的.

    纵向方位时, 每个单元宽80像素高100像素(下图展示了一个纵向方位的单元). 纵向方位支持的三种Widget尺寸为:

     

       横向方位时,每个单元宽106像素高74像素.横向方位支持的三种Widget尺寸为:

     

    标准Widget框架

    针对六种标准Widget尺寸这里有标准的框架.你可以在以下内容点击框架图片来下载该框架的Photoshop 文件用在你的Widget上.

    4x1_Widget_Frame_Portrait.psd

    3x3_Widget_Frame_Portrait.psd

    2x2_Widget_Frame_Portrait.psd

    4x1_Widget_Frame_Landscape.psd

    3x3_Widget_Frame_Landscape.psd

    2x2_Widget_Frame_Landscape.psd

    更多设计的细内容请参考此处

    http://hi.baidu.com/tdskee/blog/item/575bbcaf758559d87cd92abe.html

     

     

    展开全文
  • 一、什么是自定义Widget组件 Qt的UI设计器提供了很多GUI设计的界面组件,可以满足常见的界面设计需求。但是某些时候需要设计特殊的界面组件,而在UI设计器的组件面板里没有合适的组件,这时就需要设计自定义的界面...

    一、什么是自定义Widget组件

    • Qt的UI设计器提供了很多GUI设计的界面组件,可以满足常见的界面设计需求。但是某些时候需要设计特殊的界面组件,而在UI设计器的组件面板里没有合适的组件,这时就需要设计自定义的界面组件

    二、如何设计自定义的Widget组件

    • 所有组件的基类是QWidget,要设置自定义的界面组件,可以从QWidget继承一个自定义的类,重定义其paintEvent()事件,利用Qt的绘图功能绘制组件外观,并实现需要的其它功能
    • 然后在窗体中放置一个Widget,右击Widget组件,“Protomed to”提升为我们上面定义的那个类(看后面的演示案例)

    三、演示案例

    • 设计一个这样的电池组件

    第一步:

    • 先创建一个基于QWidget的应用窗体

    第二步:

    • 然后再添加一个从QWidget继承的类QmyBattery
    • 在此项目的基础上,点击Qt Creator的“File” ==>"New File or Project" ==>“C++ Class” ==>创建一个基于QWdiget的“qmybattery”类

    第三步:

    • 向qmybattery.h文件中书写代码,内容如下
    #include <QWidget>
    #include <QColor>
    #include <QPainter>
    
    class qmybattery : public QWidget
    {
        Q_OBJECT
    private:
        QColor mColorBack=Qt::white;  //背景色
        QColor mColorBorder=Qt::black;//电池边框颜色
        QColor mColorPower=Qt::green; //电量柱颜色
        QColor mColorWarning=Qt::red; //电量短缺时的颜色
        int mPowerLevel=60;           //当前电量(0-100)
        int mWarnLevel=20;            //电量低警示阀值
    protected:
        void paintEvent(QPaintEvent *event)Q_DECL_OVERRIDE; //绘图
    public:
        explicit qmybattery(QWidget *parent = nullptr);
        void setPowerLevel(int pow); //设置当前电量
        int powerLevel(); //得到当前电量
        void setWarnLevel(int warn); //设置电量低阀值
        int warnLevel(); //得到电量低阀值
        QSize sizeHint(); //返回组件的缺省大小
    signals:
        //当电量值改变时发射此信号
        void powerLevelChanged(int);
    public slots:
    };

    第四步:

    • 定义paintEvent()函数
    void qmybattery::paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event);
        QPainter painter(this);
        
        //设置QPainter的绘图区
        QRect rect(0,0,width(),height());
        painter.setViewport(rect);
        painter.setWindow(0,0,120,50);
        painter.setRenderHint(QPainter::Antialiasing);
        painter.setRenderHint(QPainter::TextAntialiasing);
        
        //设置画笔
        QPen pen;
        pen.setWidth(2);
        pen.setColor(mColorBorder);
        pen.setStyle(Qt::SolidLine);
        pen.setCapStyle(Qt::FlatCap);
        pen.setJoinStyle(Qt::BevelJoin);
        //设置画刷
        QBrush brush;
        brush.setColor(mColorBack);
        brush.setStyle(Qt::SolidPattern);
        
        painter.setPen(pen);
        painter.setBrush(brush);
        
        //改变rect的区域,绘制电池边框
        rect.setRect(1,1,109,48);
        painter.drawRect(rect);
        
        //改变画刷颜色,改变rect的区域,绘制电池的正极头
        brush.setColor(mColorBorder);
        painter.setBrush(brush);
        rect.setRect(110,15,10,20);
        painter.drawRect(rect);
        
        //画电池柱
        if(mPowerLevel>mWarnLevel) //正常颜色电量柱
        {
            brush.setColor(mColorPower);
            pen.setColor(mColorPower);
        }
        else//电量低时电量柱
        {
            brush.setColor(mColorWarning);
            pen.setColor(mColorWarning);
        }
        painter.setBrush(brush);
        painter.setPen(pen);
        if(mPowerLevel>0)//如果当前有电量,绘制电量柱
        {
            rect.setRect(5,5,mPowerLevel,40);
            painter.drawRect(rect);
        }
        
        //绘制电量百分比文字
        QFontMetrics textSize(this->font());
        QString powerStr=QString::asprintf("%d%%",mPowerLevel);
        QRect textRect=textSize.boundingRect(powerStr); //得到字符串的rect
        painter.setFont(this->font());
        pen.setColor(mColorBorder);
        painter.setPen(pen);
        painter.drawText(55-textRect.width()/2,23+textRect.height()/2,powerStr);;
        
    }

    第五步:

    • 定义其他成员函数
    //设置当前电量
    void qmybattery::setPowerLevel(int pow)
    {
        mPowerLevel=pow;
        emit powerLevelChanged(pow);
        repaint();
    }
    
    //得到当前电量
    int qmybattery::powerLevel()
    {
        return mPowerLevel;
    }
    //设置电量低阀值
    void qmybattery::setWarnLevel(int warn)
    {
        mWarnLevel=warn;
        repaint();
    }
    
    //得到电量低阀值
    int qmybattery::warnLevel()
    {
        return mWarnLevel;
    }
    ////返回组件尺寸大小
    QSize qmybattery::sizeHint()
    {
        int H=this->height();
        int W=H*12/5;
        QSize size(W,H);
        return size;
    }

    第六步:

    使用“提升法”,将我们自定义的类对象提升为UI组件

    • ①在UI界面中,移动一个Widget组件到主窗体中,然后右击组件,点击“Promote to”菜单项

    • ②点击之后,出现下面的UI画框

    • ③我们将“Base class name”改为“QWidget”。将Promoted class name改为“qmybattery”。勾选一些选项,然后点击Promote(如果我们有其他的自定义类也可以添加到Promoted Classes中,以便我们选择使用)

    • ④可以看到这个组件的类名称变为了qmybattery

    • ⑤右击这个组件,将其object name改为“battery”

    第七步:

    • 在主窗体中再放置一个Horizontal Slider组件和一个QLabel组件,然后与battery这个组件进行排版

    第八步:

    • 我们书写Horizontal Slider组件的valueChanged信号,然后调用setPowerLevel函数,这样的话,我们的qmybattery类就会接收到powerLevelChanged信号了

    void Widget::on_horizontalSlider_valueChanged(int value)
    {
        ui-> battery->setPowerLevel(value);
        QString str=QStringLiteral("当前电量:")+QString::asprintf("%d %%",value);
        ui->label->setText(str);
    }
    

     

    展开全文
  • Android App Widget 开发

    2020-07-10 23:30:15
    Android App Widget 开发,demo实现了一个简单的音乐播放器,详见http://blog.csdn.net/huaxun66/article/details/77880376
  • 这几天做桌面widget,现将所涉及内容整理分享给大家。写博客时间长了,觉得只是把学到的知识写出来才算是已经学会了的。这也算是强迫症了吧。今天头有点痛,心情不太好,就不多请废话了,估计也没几个人会看我的前言...

    前言:这段时间真的是有点堕落了,没怎么看书,项目也做的乱七八糟,基本没什么长进,好像男人也有生理期一样,每个月总有那么几天提不起精神,等自己彻底感到罪恶感的时候再重新整装前行。这几天做桌面widget,现将所涉及内容整理分享给大家。写博客时间长了,觉得只是把学到的知识写出来才算是已经学会了的。这也算是强迫症了吧。今天头有点痛,心情不太好,就不多请废话了,估计也没几个人会看我的前言部分,哈哈。开整吧。

     

    相关文章:

    1、《桌面widget详解(一)——基本demo构建》
    2、《桌面widget详解(二)—— 基本的与service通信》
    3、《桌面widget详解(三)——桌面widget中的控件交互方法》
    4、《桌面widget详解(四)——桌面音乐播放器(实战)》

     

    一、概述

     

    App Widget是应用程序窗口小部件(Widget)是微型的应用程序视图,它可以被嵌入到其它应用程序中(比如桌面)并接收周期性的更新。你可以通过一个App Widget Provider来发布一个Widget。官方文档地址:《App Widgets》

    这里涉及到两个方面的内容:AppWidgetProvider类和appwidget-provider标签;

    1、appwidget-provider标签:

    这个玩意是用来定义桌面widget的大小,初始状态等等信息的,它的位置应该放在res/xml文件夹下,具体的xml参数如下:

     

    • android:minWidth : 最小宽度
    • android:minHeight : 最小高度
    • android:updatePeriodMillis : 更新widget的时间间隔(ms),"86400000"为1个小时
    • android:previewImage : 预览图片
    • android:initialLayout : 加载到桌面时对应的布局文件
    • android:resizeMode : widget可以被拉伸的方向。horizontal表示可以水平拉伸,vertical表示可以竖直拉伸
    • android:widgetCategory : widget可以被显示的位置。home_screen表示可以将widget添加到桌面,keyguard表示widget可以被添加到锁屏界面。
    • android:initialKeyguardLayout : 加载到锁屏界面时对应的布局文件

     

    至于具体怎么用,等下实战的时候会讲。

    2、AppWidgetProvider类:

    上面我们通过appwidget-provider标签就可以得到初始化的布局,视图等,但我们的widget要实时更新怎么办,要响应用户操作怎么办,这就需要额外的类来辅助处理了,这个类就是AppWidgetProvider。

    由于AppWidgetProvider要接收到当前widget的状态(是否被添加,是否被删除等),所以要接收通知,必然是派生自BroadcastReceiver。

    AppWidgetProvider中的广播处理函数如下:(根据不同的使用情况,重写不同的函数)

    onUpdate():

    3种情况下会调用OnUpdate()。onUpdate()是在main线程中进行,因此如果处理需要花费时间多于10秒,处理应在service中完成。(第二篇会讲为什么还要有service)
    (1)在时间间隔到时调用,时间间隔在widget定义的android:updatePeriodMillis中设置;
    (2)用户拖拽到主页,widget实例生成。无论有没有设置Configure activity,我们在Android4.4的测试中,当用户拖拽图片至主页时,widget实例生成,会触发onUpdate(),然后再显示activity(如果有)。这点和资料说的不一样,资料认为如果设置了Configure acitivity,就不会在一开始调用onUpdate(),而实验显示当实例生成(包括创建和重启时恢复),都会先调用onUpate()。在本例,由于此时在preference尚未有相关数据,创建实例时不能有效进行数据设置。
    (3)机器重启,实例在主页上显示,会再次调用onUpdate()

    onDeleted(Context, int[]):

    当 widget 被删除时被触发。

    onEnabled(Context):

    当第1个 widget 的实例被创建时触发。也就是说,如果用户对同一个 widget 增加了两次(两个实例),那么onEnabled()只会在第一次增加widget时触发。

    onDisabled(Context):

    当最后1个 widget 的实例被删除时触发。

    onReceive(Context, Intent):

    在接收到广播时,调用。

    二、实战

    先看一下显示效果:

    就这么一个桌面widget,一个音乐播放器,这一篇只是显示出来,后面我们会慢慢完善它的功能。

    1、appwidget-provider及布局文件

    前面我们讲过,appwidget-provider提供了桌面widget的初始化显示状态、默认图标、大小等功能,但它必须放在res/xml文件夹下,看看这里的代码:

     

    <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
        android:initialLayout="@layout/example_appwidget"
        android:minHeight="60dp"
        android:minWidth="180dp"
        android:previewImage="@drawable/preview"
        android:resizeMode="horizontal|vertical"
        android:widgetCategory="home_screen|keyguard" >
    
    </appwidget-provider>

    这里有几个参数:

     

    prviewImage:就是添加桌面控件时,我们的控件在列表中的显示状态,如下图所示,下面这个丑娃娃就是我们的显示图标……

    android:initialLayout="@layout/example_appwidget":这个就是指定初始化显示时,应该显示的布局;

    下面看看这个布局文件:example_appwidget.xml

     

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#33000000"
        android:gravity="center"
        android:orientation="horizontal" >
        
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="8dip"
            android:background="@drawable/car_musiccard_up"/>
        
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="8dip"
            android:background="@drawable/car_musiccard_play"/>
        
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/car_musiccard_down"/>
    
    </LinearLayout>

    这个布局就是最上头显示出来的那个播放器的布局。

    2、ExampleAppWidgetProvider extends AppWidgetProvider

     

    在布局成功之后,下面就是根据通知实现逻辑了,这篇我们只接收通知,逻辑下篇再说。首先新建一个类ExampleAppWidgetProvider,将其派生自AppWidgetProvider;然后就会有下面的代码:

     

    public class ExampleAppWidgetProvider extends AppWidgetProvider {
    
    	 /*
    	  * 在3种情况下会调用OnUpdate()。onUpdate()是在main线程中进行,因此如果处理需要花费时间多于10秒,处理应在service中完成。
    	  *(1)在时间间隔到时调用,时间间隔在widget定义的android:updatePeriodMillis中设置; 
    	  *(2)用户拖拽到主页,widget实例生成。无论有没有设置Configure activity,我们在Android4.4的测试中,当用户拖拽图片至主页时,widget实例生成,会触发onUpdate(),然后再显示activity(如果有)。这点和资料说的不一样,资料认为如果设置了Configure acitivity,就不会在一开始调用onUpdate(),而实验显示当实例生成(包括创建和重启时恢复),都会先调用onUpate()。在本例,由于此时在preference尚未有相关数据,创建实例时不能有效进行数据设置。
    	  *(3)机器重启,实例在主页上显示,会再次调用onUpdate()
    	  */ 
    	@Override
    	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
    			int[] appWidgetIds) {
    
    		super.onUpdate(context, appWidgetManager, appWidgetIds);
    	}
    
    	// widget被删除时调用
    	@Override
    	public void onDeleted(Context context, int[] appWidgetIds) {
    		Log.d(TAG, "onDeleted(): appWidgetIds.length=" + appWidgetIds.length);
    
    		super.onDeleted(context, appWidgetIds);
    	}
    
    	// 最后一个widget被删除时调用
    	@Override
    	public void onDisabled(Context context) {
    		Log.d(TAG, "onDisabled");
    
    		super.onDisabled(context);
    	}
    
    	// 第一个widget被创建时调用
    	@Override
    	public void onEnabled(Context context) {
    
    		super.onEnabled(context);
    	}
    
    	// 接收广播的回调函数
    	@Override
    	public void onReceive(Context context, Intent intent) {
    
    		super.onReceive(context, intent);
    	}
    }

    这里不是继承接口,这几个函数并不是需要全部重写的,根据需要,要用到哪个可以重写哪个。

    3、注册ExampleAppWidgetProvider

    前面我们讲到AppWidgetProvider派生自BroadcastReciver,所以要提前注册,有关BroadcastReciver的注册有两种方法,静态注册和动态注册,因为这里要接收来自的消息,而且在程序启动时就开始自动监听,所以,这里需要静态注册。有关BroadcastReciver的问题,可以参看《BroadcastReceiver详解》

     

    <!-- 声明widget对应的AppWidgetProvider -->
    <receiver android:name=".ExampleAppWidgetProvider" >
        <intent-filter>
    	<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data android:name="android.appwidget.provider"
    	android:resource="@xml/example_appwidget_info" />
    </receiver>

    (1)接收的action定义为:"android.appwidget.action.APPWIDGET_UPDATE"这表明接收系统发来的有关这个app的所有widget的消息(主要是增加、删除)。

     

    (2)<meta-data> 指定了 AppWidgetProviderInfo 对应的资源文件
    android:name -- 指定metadata名,指定为android.appwidget.provider表示这个data中的数据是AppWidgetProviderInfo 类型的
    android:resource -- 指定 AppWidgetProviderInfo 对应的资源路径。即,xml/example_appwidget_info.xml。
     

    三、可能出现的错误:

    1、有关布局错误

    在构造Widget布局时,App Widget支持的布局和控件非常有限,有如下几个:

    App Widget支持的布局:

    •   FrameLayout
    •   LinearLayout
    •   RelativeLayout
    •   GridLayout

     

     App Widget支持的控件:

    •   AnalogClock
    •   Button            
    •   Chronometer
    •   ImageButton
    •   ImageView
    •   ProgressBar
    •   TextView
    •   ViewFlipper
    •   ListView
    •   GridView
    •   StackView
    •   AdapterViewFlipper

     

    除此之外的所有控件(包括自定义控件)都无法显示,无法显示时,添加出来的widget会显示“加载布局出错”

    2、appwidget-provider出现错误

    如果appwidget-provider页面出现错误提示:error: No resource identifier found for attribute 'widgetCategory' in package 'android'

    这是由于build target应该在17以上,有两种方法解决:

    方法1:找到工程中的project.properties文件将target=android-14改为target=android-17   

    方法2:工程上右键-》properties  选择Android,将Project Build Target改为17或以上,如图:(改完之后rebuild一下工程)

     

     

     

    如果我的文章有帮到你,记得加关注哦!

    源码来啦,本文所涉及源码下载地址:http://download.csdn.net/detail/harvic880925/8193853

    请大家尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/41445407  谢谢!

     

    如果你喜欢我的文章,你可能更喜欢我的公众号

    启舰杂谈

     

    展开全文
  • widget窗口小部件

    2016-05-19 17:15:09
    Appwidget就是手机应用中常常放在桌面(即home)上的一些应用程序,比如...1、widget类的定义 首先,在res目录下新建一个名为xml的文件夹,在该文件夹下新建一个xml文件,例如example_appwidget_info.xml,该xml文件的根标

     Appwidget就是手机应用中常常放在桌面(即home)上的一些应用程序,比如说闹钟等。这种应用程序的特点是它上面显示的内容能够根据系统内部的数据进行更新,不需要我们进入到程序的内部去,比如说闹钟指针的摆动等。


    1、widget类的定义


    首先,在res目录下新建一个名为xml的文件夹,在该文件夹下新建一个xml文件,例如example_appwidget_info.xml,该xml文件的根标签为appwidget-provider. 该xml文件主要是对所建立的appwidget的一个属性设置,其中比较常见的属性有appwidget更新的时间,其初始的布局文件等等。

    res/xml/example_appwidget_info下内容如:

    <appwidget-providerxmlns:android="http://schemas.android.com/apk/res/android"

        android:minWidth="40dp"                    <!-- 最小宽度 -->
        android:minHeight="40dp"                   <!-- 最小高度 -->
        android:updatePeriodMillis="86400000"              <!-- 更新间隔时间,最短也得设置半个小时 -->
        android:previewImage="@drawable/preview"   <!-- 预览的样子图片,可以不需要,默认为应用logo -->
        android:initialLayout="@layout/example_appwidget"  <!-- 布局文件 -->
        android:configure="com.example.android.ExampleAppWidgetConfigure" <!-- 配置页面是一个Activity,有些应用在添加widget后需要跳转页面进行配置 -->
        android:resizeMode="horizontal|vertical"  <!-- 缩放模式,水平方向竖直方向都支持缩放 -->

        android:widgetCategory="home_screen|keyguard">  <!-- 4.2+以上支持锁屏页展示widget, home_screen普通类型-->

        <!-- 4.2+系统的锁屏页添加widget:  android:widgetCategory="keyguard|home_screen"-->

    </appwidget-provider>

    系统自带的更新设置最短也得半个小时才会更新一次,而如果我们需要更短时间更新时,可以把android:updatePeriodMillis="0"置为0,然后自定义一个Service在onCreate方法中定义一个定时器Timer去实现更新;而在自定义的widget的AppWidgetProvider类型java类中的onEnabled和onUpdate方法中开启Service,在onDisabled方法中结束Service。

    其次, 定义一个类,例如ExampleAppWidgetProvider.java继承AppWidgetProvider,同时要在清单文件AndroidManifest.xml中进行配置。配置如下所示

    <receiver android:name="ExampleAppWidgetProvider" >
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>
        <meta-data android:name="android.appwidget.provider"
                   android:resource="@xml/example_appwidget_info" />
    </receiver>
    android:resource - 详述AppWidgetProviderInfo资源的位置,在res目录下新建一个文件xml,在xml文件夹下自定义一个widget属性集的xml文件,

    该类能实现所建立的widget的全部功能,其中比较重要的功能是接收广播消息来更新widget的内容。该类能复写父类的所有方法,例如onReceive方法,但widget还具备自身的方法,例如onEnabled,onUpdate,onDeleted,onDisabled等方法。

    其中onDeleted()方法是当appwidget删除时被执行,

    onDisabled()是当最后一个appwidget被删除时执行,

    onEnabled()为当第一个appwidget被建立时执行,

    onReceive()为当接收到了相应的广播信息后被执行(在每次添加或者删除widget时都会执行,且在其它方法执行的前面该方法也会被执行,其实本质上该方法不是AppWidgetProvider这个类的生命周期函数),

    onUpdate()为到达了appwidget的更新时间或者一个appwidget被建立时执行。

    appwidget中本身里面就有程序(有activity),但是在桌面上添加一个appwidget后也相当于一个程序,这2个程序本身不是在同一个进程当中,而是在各自单独的进程中。


    widget本质上是一个BroadcastReceiver,所以Receiver有的方法widget都有例如OnReceiver方,widget还有自身具备的方法:

        //第一次添加widget时调用此方法
        @Override
        public void onEnabled(Context context) {
            // TODO Auto-generated method stub
            super.onEnabled(context);
        }
        
        //widget被更新时调用此方法
        //更新的情况有两种:
        //1、桌面新增widget,例如:桌面原来没有widget,现在增加一个
        //2、widget间隔一定时间更新,xml文件中配置的
        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager,
                int[] appWidgetIds) {
            // TODO Auto-generated method stub
            super.onUpdate(context, appWidgetManager, appWidgetIds);
        }
        
        //widget被移除时调用此方法,例如桌面原来有两个widget,现在删除一个
        @Override
        public void onDeleted(Context context, int[] appWidgetIds) {
            // TODO Auto-generated method stub
            super.onDeleted(context, appWidgetIds);
        }
        
        //最后一个widget被移除的时候调用此方法
        @Override
        public void onDisabled(Context context) {
            // TODO Auto-generated method stub
            super.onDisabled(context);
        }


    2、widget生命周期及相关实验


    例一:

      实验说明:

      这个例子实现一个最简单的appwidget,即我们的appwidget只有一个按钮,按钮上面写着“我的常用密码字样”,没有其它功能,呵呵。然后我们在appwidget的java类的程序中,每个生命周期函数都在后台打印出一句话,内容是与该生命周期函数名相对应的。

      实验结果:

      往桌面添加自己创建的一个appwidget效果如下所示:

      

     

      该实验室先后在桌面上放2个appwidget,然后依次删除2个appwidget,则程序后台的输出结果如下所示:

      

     

      实验主要代码及注释(附录有实验工程code下载链接):

      MainActivity.java不用更改任何代码,采用默认的就行了,这里就不贴出来了。

    my_passward_provider.java(Appwidget功能实现):

    复制代码
    package com.example.appwidget1;
    
    import android.appwidget.AppWidgetManager;
    import android.appwidget.AppWidgetProvider;
    import android.content.Context;
    import android.content.Intent;
    
    public class my_password_provider extends AppWidgetProvider {
    
        @Override
        public void onDeleted(Context context, int[] appWidgetIds) {
            // TODO Auto-generated method stub
            System.out.println("appwidget--->onDeleted()");
            super.onDeleted(context, appWidgetIds);
        }
    
        @Override
        public void onDisabled(Context context) {
            // TODO Auto-generated method stub
            System.out.println("appwidget--->onDisabled()");
            super.onDisabled(context);
        }
    
        @Override
        public void onEnabled(Context context) {
            // TODO Auto-generated method stub
            System.out.println("appwidget--->onEnabled()");
            super.onEnabled(context);
        }
    
        @Override
        public void onReceive(Context context, Intent intent) {
            // TODO Auto-generated method stub
            System.out.println("appwidget--->onReceive()");
            super.onReceive(context, intent);
        }
    
        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager,
                int[] appWidgetIds) {
            // TODO Auto-generated method stub
            System.out.println("appwidget--->onUpdate()");
            super.onUpdate(context, appWidgetManager, appWidgetIds);
        }
        
    }
    复制代码

     

    res/xml/my_password.xml:

    复制代码
    <?xml version="1.0" encoding="utf-8"?>
    <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" 
        android:minWidth="200dp"
        android:minHeight="100dp"
        android:updatePeriodMillis="600000"
        android:initialLayout="@layout/my_password_initillayout"
        >
    </appwidget-provider>
    复制代码

     

    res/layout/my_password_initilayout.xml:

    复制代码
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
        <Button 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/my_appwidget"
            />
    
    </LinearLayout>
    复制代码

     

     

     

      例二:

      该实验的目的主要是学会在appwidget中使用PendingIntent和RemoteViews这2个类,并最终对它们有一定的了解。

      实验说明:

      这个例子在上面的例子中多增加了一个功能,即当我们把appwidget添加到桌面上的时候(上面那个例子是个按钮),单击这个按钮,这个时候程序会从home界面跳转到其它activity界面。那么怎么实现监听appwidget上的按钮控件呢?这里实现该过程与在activity中的方法不同。在此之前,我们需要了解2个概念。

     

      PendingIntent:

      PendingIntent与以前我们的Intent不同,以前我们新建一个intent时,立刻就用它启动一个activity,或者启动一个service,亦或是发送一个broadcast。这里我们新建一个PendingIntent后,按照字面意思并不马上使用它,而是当我们需要使用它的时候再启动,比如说当某一事件需要响应时,我们这时候可以使用建立好了的PendingIntent了。一个PendingIntent中包含了一个intent。Mars老师把PendingIntent比作成三国中的“精囊妙计”,从下面mars老师的2张示意图中可以更深一步了解PendingIntent。

      建立PendingIntent示意图:

      

     

      响应PendingIntent示意图:

      

     

      RemoteViews:

      RemoteView代表了与调用它的那个activity不在同一个进程的view,因此叫做”远程view”。在appWidget中使用这个类就可以实现当对appwidget的那个进程进行操作时响应其它进程中的activity。而RemoteViews则表示了一系列的RemoteView。

      实验结果与例一一样,只不过是在单击appwidget上的按钮时,会自动跳转到相应的activity上。这里就不截图看效果了。

     

      实验主要部分及代码(附录有实验工程code下载链接):

      其它部分与例一都差不多,只不过是在appwidget生命周期的onUpdate()函数不同,下面是对应其文件的java代码:

    复制代码
    package com.example.appwidget1;
    
    import android.app.PendingIntent;
    import android.appwidget.AppWidgetManager;
    import android.appwidget.AppWidgetProvider;
    import android.content.Context;
    import android.content.Intent;
    import android.widget.RemoteViews;
    
    public class my_password_provider extends AppWidgetProvider {
    
        @Override
        public void onDeleted(Context context, int[] appWidgetIds) {
            // TODO Auto-generated method stub
            System.out.println("appwidget--->onDeleted()");
            super.onDeleted(context, appWidgetIds);
        }
    
        @Override
        public void onDisabled(Context context) {
            // TODO Auto-generated method stub
            System.out.println("appwidget--->onDisabled()");
            super.onDisabled(context);
        }
    
        @Override
        public void onEnabled(Context context) {
            // TODO Auto-generated method stub
            System.out.println("appwidget--->onEnabled()");
            super.onEnabled(context);
        }
    
        @Override
        public void onReceive(Context context, Intent intent) {
            // TODO Auto-generated method stub
            System.out.println("appwidget--->onReceive()");
            super.onReceive(context, intent);
        }
    
        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager,
                int[] appWidgetIds) {
            // TODO Auto-generated method stub
        //    System.out.println("appwidget--->onUpdate()");
            for(int i = 0; i < appWidgetIds.length; i++)
            {
                System.out.println(appWidgetIds[i]);
                //该构造函数之间把跳转的2个activity给联系起来了
                Intent intent =  new Intent(context, MyPasswordActivity.class);
                //创建一个PendingIntent
                PendingIntent pendint_intent = PendingIntent.getActivity(context, 0, intent, 0);
                //创建一个remoteview对象,第2个参数为appwidget的初始布局文件
                RemoteViews remote_views = new RemoteViews(context.getPackageName(), R.layout.my_password_initillayout);
                //为RemoteViews中的button按钮添加监听器,第二个参数为PendingIntent类型,当事件触发时才执行
                remote_views.setOnClickPendingIntent(R.id.my_password, pendint_intent);
                //更新appwidget
                appWidgetManager.updateAppWidget(appWidgetIds[i], remote_views);
            }
            super.onUpdate(context, appWidgetManager, appWidgetIds);
        }
        
    }
    复制代码

     

     

     

      例三:

      实验说明

      这个例子在例二的基础上增加一些功能,即利用appwidget的onUpdate()方法中发送广播信息,然后在onReceive()方法中来接收广播消息,从而来更改appwidget的外观,这里是更改它的图片和文本显示。

      这个例子不像上面那样采用getActivity来创建PendingI,而是采用的getBroadcast,因为这里需要的是发送广播信息,而不是跳转到另一个activity。

    同样的,需要啊manifest.xml文件中队appwidget这个类来注册它的接收器,action过滤时采用的是自己定义的action,名字可以自己随便取,保证不和系统提供的action名字相同即可,该程序中采用的是"my.action.APPWIDGET_UPDATE"这个名字。

      Appwidget中有1个按钮,一个ImageView,一个TextView。程序实现的是这么一个功能:appwidget在桌面被创建时,imageview和textview都有各自的内容,当按钮按下时,这2个控件的内容都会发生变化,这种变化都是通过RemotViews的方法实现的。其中imageview是用的setImageViewResource()函数,textview是用的setTextViewText()函数。

      从上面的解释可以看到,为什么在同一个类(这里指继承AppWidgetProvide的那个类)中,从onUpdate()函数发送出去的广播能够在onReceiver()函数里接收呢?这是因为AppWidgetProvider的其它4个生命周期函数的执行都是由onReceiver分发下去的。由mars老师提供的这张示意图可以看出它们之间的关系:

      

     

      实验结果:

      桌面上创建appwidget时显示如下:

      

     

      单击按钮后,显示如下:

      

     

     

      实验主要部分代码即注释(附录有实验工程code下载链接):

    AndriodManifest.xml:

    复制代码
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.appwidget1"
        android:versionCode="1"
        android:versionName="1.0" >
    
        <uses-sdk
            android:minSdkVersion="8"
            android:targetSdkVersion="15" />
    
        <application
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name=".MainActivity"
                android:label="@string/title_activity_main" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <receiver android:name=".my_password_provider" >
                <intent-filter>
                    <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                </intent-filter>
                <intent-filter>
                    <action android:name="my.action.APPWIDGET_UPDATE"/>
                </intent-filter>
                <meta-data
                    android:name="android.appwidget.provider"
                    android:resource="@xml/my_password" />
            </receiver>
            <activity
                android:name=".MyPasswordActivity"
                android:label="@string/title_activity_my_password" >
            </activity>
        </application>
    
    </manifest>
    复制代码

     

    my_password_provider.java(里面有appwidget的生命周期函数):

    复制代码
    package com.example.appwidget1;
    
    import android.app.PendingIntent;
    import android.appwidget.AppWidgetManager;
    import android.appwidget.AppWidgetProvider;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.Color;
    import android.widget.RemoteViews;
    
    public class my_password_provider extends AppWidgetProvider {
        
        private static final String MY_ACTION = "my.action.APPWIDGET_UPDATE";
        @Override
        public void onDeleted(Context context, int[] appWidgetIds) {
            // TODO Auto-generated method stub
            System.out.println("appwidget--->onDeleted()");
            super.onDeleted(context, appWidgetIds);
        }
    
        @Override
        public void onDisabled(Context context) {
            // TODO Auto-generated method stub
            System.out.println("appwidget--->onDisabled()");
            super.onDisabled(context);
        }
    
        @Override
        public void onEnabled(Context context) {
            // TODO Auto-generated method stub
            System.out.println("appwidget--->onEnabled()");
            super.onEnabled(context);
        }
    
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if(MY_ACTION.equals(action))
            {
                RemoteViews remote_views = new RemoteViews(context.getPackageName(), R.layout.my_password_initillayout);
                //更改appwidget界面中的图片
                remote_views.setImageViewResource(R.id.my_image, R.drawable.no);
                //更改appwidget界面中textview中的文字内容
                remote_views.setTextViewText(R.id.my_text, "no");
                remote_views.setTextColor(R.id.my_text, Color.RED);
                //获得本context的AppWidgetManager
                AppWidgetManager appwidget_manager = AppWidgetManager.getInstance(context);
                //新建一个ComponentName,该ComponentName指的是针对appwidget整体而言的;而RemoteViews是针对appwidget
                //中各个部件之和而言的,这两者有些区别
                ComponentName component_name = new ComponentName(context, my_password_provider.class);
                //上面2句代码是为下面更新appwidget做准备的
                appwidget_manager.updateAppWidget(component_name, remote_views);        
            }
            else
                super.onReceive(context, intent);
        }
    
        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager,
                int[] appWidgetIds) {
            // TODO Auto-generated method stub
            Intent intent = new Intent();
            intent.setAction(MY_ACTION);
            //以发送广播消息的方式创建PendingIntent.
            PendingIntent pending_intent = PendingIntent.getBroadcast(context, 0, intent, 0);
            //创建一个remoteviews,其布局文件为appwidget的初始布局文件
            RemoteViews remote_views = new RemoteViews(context.getPackageName(), R.layout.my_password_initillayout);
            //为按钮添加监听器
            remote_views.setOnClickPendingIntent(R.id.my_password, pending_intent);
            //更新appwidget
            appWidgetManager.updateAppWidget(appWidgetIds, remote_views);
            
            super.onUpdate(context, appWidgetManager, appWidgetIds);
        }
        
    }
    复制代码

     

    res/layout/my_password_initillayout.xml(appwidget的布局文件):

    复制代码
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
    
        <Button
            android:id="@+id/my_password"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/my_appwidget" />
    
        <ImageView
            android:id="@+id/my_image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dip"
            android:src="@drawable/yes"
             />
        <TextView
            android:id="@+id/my_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/yes"
            android:textColor="#0000ff"
            />
    
    </LinearLayout>
    复制代码

     

    Res/xml/my_password.xml(appwidget的属性设置xml文件):

    复制代码
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
    
        <Button
            android:id="@+id/my_password"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/my_appwidget" />
    
        <ImageView
            android:id="@+id/my_image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dip"
            android:src="@drawable/yes"
             />
        <TextView
            android:id="@+id/my_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/yes"
            android:textColor="#0000ff"
            />
    
    </LinearLayout>
    复制代码

     

      总结:通过这几个例子,可以初步了解创建一个appwidget的整个流程,并且学会了简单的是appwidget和其它的进程间进行通信。

     

         参考资料:

         http://www.mars-droid.com/bbs/forum.php

        仿今日头条的AppWidget https://github.com/benniaobuguai/opencdk-appwidget

     

         附录:

         实验工程code下载



    展开全文
  • Widget的简单使用详解

    2019-10-31 18:29:18
    Widget是安卓的一个桌面小工具组件—窗口小部件,是微型应用程序视图,可以嵌入到其他应用程序(如主屏幕)和接收定期更新。 使用步骤: 1、创建一个类继承AppWidgetProvider 并重写相应方法 默认实现了onReceive ...
  • QWidget

    2017-06-06 19:13:12
    QWidget最近在学习Qt,每次阅读官方英文API都只读取自己需要的一部分,但是面对庞大的英文,老是觉得获取信息像大海捞针一样困难。于是我决定从头到尾好好读一读英文介绍,然后根据自己的理解,把它翻译为中文,一...
  • AppWidget(详细解析)

    2016-05-09 20:11:59
    1 Android widget  Android widget 也称为桌面插件,其是android系统应用开发层面的一部分,但是又有特殊用途,而且会成为整个android系统的亮点。Android中的AppWidget与google widget和中移动的widget并不是一...
  • Widget是Android应用小部件,它可以作为一个微型视图嵌套在其他应用程序中(比如可以放置在桌面),并接收周期性更新。通常来说,小部件可以通过与App交互更方便的将App的内容展示给用户,同时它也是App的一个便捷...
  • AppWidget:基本使用

    2017-03-21 17:42:27
    App Widget是应用程序窗口小部件(Widget)是微型的应用程序视图,它可以被嵌入到其它应用程序中(比如桌面)并接收周期性的更新。你可以通过一个App Widget Provider来发布一个Widget。 本文参考Android官方文本,...
  • 这个词当然就是“widget”了。虽然已经有很多人开始谈论widgets的2.0版本,但是大部分的人才刚刚开始注意到它。你可能会觉得widgets是最烦人的时尚,或者是社会互动中极具创意的潮流。不管怎样,widgets已经成为我们...
  • 前言:其实桌面widget桌面交互也是一个大坑,我在开发中遇到了真是一个又一个的问题,其中问题很多,主要原因还是android对widget的支持不够完美,比如remoteView传送数据太大就会崩等,无缘无故widget不响应等等,...
  • 前言:这将是这个系列的最后一篇了,我写这几篇文章也是累的快不行了,再写就真的要吐了,言归正转,前面三篇已经把widget中涉及到的基本知识基本上讲完了,今天我们就做一个小例子,看看桌面音乐播放器widget是怎么...
  • Odoo10 widget标签整理

    2018-12-28 20:30:50
    widget="statusbar" 头部状态条标签  widget="many2many_binary" 可以看小图的标签 widget="email" 电子邮件地址标签  widget="selection" 下拉选择标签 widget=&...
  • ThinkPHP3.2 Widget扩展

    2015-11-24 11:26:08
    我暂时对Widget的理解,就是一些页面有相同的地方例如导航栏(这里只是举个例子),当然我们可以用thinkphp的继承模板来实现,但是有些页面不需要导航栏,我们就可以用Widget的扩展,用W()函数调用他。 Widget最...
  • ios8新特性widget开发

    2015-03-02 19:41:05
    其中一个新特性就是在下拉通知栏里加入了个性的widget,开发者可以自己定义widget的样式内容。当然这个功能在Android上早就实现了,^_^.........,如下图: 首先先说几个概念, 1、app extension:extension是iOS8...
  • odoo视图中常用widget

    2019-01-11 11:06:33
    widget=&amp;quot;statusbar&amp;quot; 头部状态条标签 widget=&amp;quot;email&amp;quot; 电子邮件地址标签 widget=&amp;quot;selection&amp;quot; 下拉选择标签 widget=&amp;quot;...
  • 桌面Widget其实就是一个显示一些信息的工具(现在也有人开发了一些有实际操作功能的widget。例如相机widget,可以直接桌面拍照)。不过总的来说,widget主要功能就是显示一些信息。我们今天编写一个很简单的作为...
  • 作为系列文章的第六篇,本篇主要在前文的探索下,针对描述一下 Widget 中的一些有意思的原理。 前文: 一、Dart语言和Flutter基础 二、 快速开发实战篇 三、 打包与填坑篇 四、Redux、主题、国际化 五、 ...
  • 最近需要编写一个日期时间的桌面Widget用来关联日历程序,以前很少写桌面Widget。对这方面技术不是很熟悉,今天花时间重新整理了一下,顺便把编写一个简单时间日期程序过程记录下来。 桌面Widget其实就是一个显示...
1 2 3 4 5 ... 20
收藏数 359,466
精华内容 143,786
关键字:

widget