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

     

     

    展开全文
  • 什么是widgetwidget是什么意思?

    万次阅读 2010-04-07 09:53:00
    这个词当然就是“widget”了。虽然已经有很多人开始谈论widgets的2.0版本,但是大部分的人才刚刚开始注意到它。你可能会觉得widgets是最烦人的时尚,或者是社会互动中极具创意的潮流。不管怎样,widgets已经成为我们...

     在过去几年,一个新术语进入了营销词汇的行列。这个词当然就是“widget”了。虽然已经有很多人开始谈论widgets的2.0版本,但是大部分的人才刚刚开始注意到它。你可能会觉得widgets是最烦人的时尚,或者是社会互动中极具创意的潮流。不管怎样,widgets已经成为我们行内对话的一部分了。这段时间widgets可谓是无所不在。和发行商、销售人员或者同事的对话,或者所阅读的文章、参加的会议等,都是围绕着这个词及其相关主题进行的。而他们的讨论的重点通常是关于widget的定义—而不是什么时候、该如何使用,或者谁出色地使用了它。

     

          全世界各地举行的市场销售讨论会议上,除了widget的定义外,讨论得最多的就是 怎么的东西才能被认可为widget。取决于公司不同的规模和业务重点,还有你在公司中担当的角色,你可能会对这个“新”事物的命名有自己的看法。可以是widget(小部件),gadget(小玩具),desktop application(桌面的应用软件),downloadable application(可下载的应用程序),或者是其他你公司自创的新鲜名称。

          紧接着,我们一起来认真思考一下widgets是什么,为什么要被使用,何时该被使用,谁来使用,如何使用等等问题。听到关于widget的各种定义后,我在Dictionary.com查找了widget的意思。正如我所想,结果和讨论一样多样:

          Widget-名词—①一个小机械设备,如球形柄或者开关装置,特别是一些没有或者想不起具体名称的物品。Gadget(新奇的小玩意):在仪器板上一排的widgets。②在用户的图形界面上,为了实现一个具体的功能(例如卷轴或者按钮)而使用的系列图形符号和程序代码。③为某项任务特定的设备或者操纵装置--通常提供包含设定模式而行为一致的常用的widgets的widget库。

          或者再看看FreeWebs.com上这个简单的,更内行的定义—widgets是能使你的网站更有个性,更特别的小的分块特征。

          其中一些定义的确与我们行业的日常活动息息相关。为了能继续我们的论述,我们假定在这个文章中提及的widgets包括①大众网页的widgets ②品牌为促进参与、销售和发展及(或)广告收益特别制作的widgets③更复杂些的可下载的多功能的widgets或者桌面应用程序。最后我想说说,这些widgets的共同点在于他们都以促进某种顾客行为(购买/收益,品牌意识/参与,传承等等)为目的。 

          为什么/何时我应该关注widgets?

          过去几年,很多品牌都已经利用了widgets。随着widgets工具的使用和市场化渐趋日常,很自然就会有更多的营销商就widgets是否适用于自己公司提出疑问。对于希望在拥挤的网络上建立吸引力和忠诚顾客群的发行者,或者努力于在自己的品牌和顾客间建设更方便的沟通桥梁的零售商,或者渴望创造下一个伟大的widget的雄心壮志的开发者,实在有太多理由去关注widgets了。但是你呢?你需要关注widgets吗?如果需要的话,又是基于什么理由呢?

          行业内不断产生一些量度widget有效性(不仅仅是指有多少人使用了你的widget)和对行业预期的促进效果评估的标准。 难度在于,基于不同目的的widget实在种类繁多。一些只是简单地宣传品牌,一些是纯熟的信息发布策略的一部分,更有一些是支持新产品、服务、电影等等的工具。当然你还可以赞助或者在别人的widget上投放广告,或者建立自己的widget……但是,当我们只是用轶闻趣事作为我们决定谁应该关注widgets的依据时,就这样一个原因就足以使所有的市场营销人员迷上widget了—widgets的世界充满机遇!但是不要忘了:同时也有很多失败的投资反例,足以吓跑那些刚进入widget世界的人了。

          因而,尽管有很多围绕着widgets世界重大突破的热火朝天的报道,widget是否能成功依然没人能打包票。所以说,公司在着手创造自己的widget的时候,应该考虑以下几点:

    1. 创造widget还是不足够的。在开始你的创造之旅前要好好地做些功课,看看widget是否适用于自己。考虑网站造访者或者品牌对象的所需,以及你要创造的widget是否实现简捷,具娱乐性,令人难忘和值得一提的。如果你满怀信心,觉得自己能打出个全垒打,觉得基于你的考虑和顾客的需求下widget的确是你必要的选择,那么是时候你要考虑如何推出你的widget,使它能脱颖而出并且持续保有竞争力了。

    2. 我需要的widget建设理念已经存在了吗?在如今这个充满竞争的社会,很多的idea可能都已经存在了。但是这并不意味着你不能对这些现有的概念进行改进/改造。关键在于你应该意识到这些概念的存在并且想出改进/改造的最佳方案,从而实现你的widget和使用者间的最优互动。

    3. 设定你的目标和效用评估标准。虽说行业的widget效用评估标准已在制订中了,但是于大部分的公司来说,只有自己才最清楚知道自己所需。你可能是出版商--为直接影响利益的读者量而努力;你可能是一个品牌网站的经营者—希望你的客户下载/使用你提供的应用程序;你也可能为分销商提供你的widget/销售引擎,优化他们和顾客间的营销行为。如果你不能很好地设定,要取得成功几乎不可能。同时,这个过程也能帮助你分析你应该和谁合作,应该投资多少等问题。

          什么时候我应该开发widget?

          同事、上司还有同行的朋友问我这个问题的时候,我会先和他们回顾一下以上我说的几点--要他们先考虑清楚他们是否需要参与到关于widgets的讨论中去。这的确是由你的目标、预算和顾客基础决定的。你的顾客会对widgets感冒吗?它有助于你把你的品牌推向另一个高度吗?你有足够的预算抵御冲击和错失吗?

          在你决定现在要你的队伍着手开发下一个伟大的widget工具的时机是否已经来临之前,或许你该考虑以下由iMediaConnection.com的同事的建议。他的文章“Avoid these Facebook faux pas”写得相当有深度。其中的至理名言有:“先好好地自我反省一下。你着手加入这场(在我这篇文章中是关于widget的)社会化媒体运动,是不是仅仅因为别人认为这样做很酷?抑或是因为它符合发展更多方法的理念?其实只需要把它看作是众多销售渠道之一,好好考虑就对了--一旦它被认定为不能成就全局战略,它便有可能失败。”

          虽然是针对社会化媒体运动而写的,他的这番言论依然与widget的话题相关。我实在想不到更好的办法去论证了。因此借用一下Evan的妙论了。谢谢Evan!

           谁在使用widgets?

          在每天都有新的widgets冒出来的市场上显然还是有一些先锋角色的。他们以发展,创新和成功作为标准建设自己的widgets。以下我列举其中几个我认为做得不错的网站。

    Tripadvisor(旅行顾问--免费旅游指南网站)

         tripadvisor网站的访问者会发现,下载网站提供的“我所访问过的城市”的widget时,向导和价值定位都相当简单。但是,其功能和效应可以说是好得不得了。这个widget会提问:“你去过哪个城市了?”创造一个可以与朋友分享/互动的旅游地图,帮助他们规划行程。我认识的所有人几乎都在使用这个widget—从十几岁的堂兄弟到60岁的岳父都在使用。我要马上计划我的旅游行程了!做得不错的网站!

    ILike(我喜欢)

         如果你经常上网,可能你也听过iLike这个网站了。引用网页的描述来介绍它吧:在iLike网站,你可以为你的档案添加音乐和视频,向你的朋友推荐音乐,查看谁去看了什么音乐会。还可以免费下载你喜欢的 mp3。你或许能在音乐常识竞赛(Music Challenge)中 打败你的朋友了!


          这些受欢迎的widget有一个共同的基本要点:为客户实现想法提供了便利的手段。譬如:和朋友讨论最喜欢的音乐/视频;看看他们和朋友都分享了什么最爱;测试他们的音乐知识;还有就是分享内容、贡献曲目。这样的开始是轻松的--价值观清晰,完全和目标客户相关。难怪它能取得巨大的成功了。

    http://info.codepub.com/2008/06/info-19918.html

    http://www.iciba.com/WIDGETS/

    http://www.w3.org/TR/widgets/

     

    展开全文
  • Android列表小部件(Widget)开发详解

    万次阅读 热门讨论 2020-09-27 16:57:53
    Widget是Android应用小部件,它可以作为一个微型视图嵌套在其他应用程序中(比如可以放置在桌面),并接收周期性更新。通常来说,小部件可以通过与App交互更方便的将App的内容展示给用户,同时它也是App的一个便捷...

    好久没博客更新了,本篇文章来学习一下如何实现一个Android列表小部件,效果可以参看下图:
    在这里插入图片描述

    这个页面如果是在App内部实现,相信只要有一点Android基础的童鞋都能很轻松写出来。但是如果放到Widget中可能就不是那么简单了。因为Widget并没有运行在我们App的进程中,而是运行在系统的SystemServer进程中。你可能会惊讶,Whf!竟然不在我们App进程中!那么是不是意味着我们也不能像在App中那样操作View控件了?答案确实如此。不过不必过于担心,为了我们能在远程进程中更新界面,Google爸爸专门为我们提供了一个RemoteViews类。从名字上看,可能会觉得RemoteViews就是一个View。但事实并非如此,RemoteViews仅仅表示的是一个View结构。它可以在远程进程中展示和更新界面。今天我们要实现的列表小部件就是基于RemoteVeiw实现的。
    那么接下来我们来学习如何实现一个桌面Widget,我们先列出要实现Widget的几个核心步骤:

    • widget页面布局
    • 小部件配置信息
    • 了解AppWidgetProvider
    • RemoteViewsFactory实现列表适配
    • 点击的事件处理

    一. 实现Widget界面

    **1.widget页面布局。**首先创建一个布局文件layout_widget.xml,内容如下:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/ll_right"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/bg_widget"
        android:orientation="vertical">
    
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:background="#ccc">
    
            <ImageView
                android:id="@+id/iv_icon"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:layout_centerVertical="true"
                android:layout_marginEnd="5dp"
                android:layout_marginStart="5dp"
                android:background="@mipmap/ic_launcher_round" />
    
            <TextView
                android:id="@+id/tv_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_toEndOf="@id/iv_icon"
                android:text="Widget" />
    
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_alignParentEnd="true"
                android:gravity="center_vertical"
                android:orientation="horizontal">
    
                <ProgressBar
                    android:id="@+id/progress_bar"
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:indeterminateTint="@color/colorAccent"
                    android:indeterminateTintMode="src_atop"
                    android:visibility="gone" />
    
                <TextView
                    android:id="@+id/tv_refresh"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginEnd="15dp"
                    android:text="刷新"
                    android:padding="5dp"
                    android:textSize="12sp" />
            </LinearLayout>
    
        </RelativeLayout>
    
        <ListView
            android:id="@+id/lv_device"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:columnWidth="80dip"
            android:gravity="center"
            android:horizontalSpacing="4dip"
            android:numColumns="auto_fit"
            android:verticalSpacing="4dip" />
    
    </LinearLayout>
    

    看到布局中的ListView控件,你可能会不屑一笑,都什么年代了还在用ListView?RecyclerView才是王道吧?可是我只能说句抱歉,Widget不支持RecyclerView。对,你没看错,真的不支持。在Widget中我们没办法做到想用什么就用什么,甚至觉得原生用着不爽,自己撸一个控件出来。对不起,Widget都不支持。因此Widget也有很大的局限性。我们来看下支持在Widget中运行的有哪些控件:

    A RemoteViews object (and, consequently, an App Widget) can support the following layout classes:
    FrameLayout
    LinearLayout
    RelativeLayout
    GridLayout
    And the following widget classes:
    AnalogClock
    Button
    Chronometer
    ImageButton
    ImageView
    ProgressBar
    TextView
    ViewFlipper
    ListView
    GridView
    StackView
    AdapterViewFlipper
    Descendants of these classes are not supported.

    除了上述列出的几个View,其它的包括Android原生View和自定义View是都不支持在Widget中运行的。因此基于Widget页面限制我们基本就可以告别炫酷的动画效果了。

    二.小部件配置信息

    配置信息主要是设定小部件的一些属性,比如宽高、缩放模式、更新时间间隔等。我们需要在res/xml目录下新建widget_provider.xml文件,文件名字可以任意取。文件内容如下(可做参考):

    <?xml version="1.0" encoding="utf-8"?>
    <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
        android:minHeight="180dp"
        android:minWidth="300dp"
        android:previewImage="@drawable/ic_launcher_background"
        android:initialLayout="@layout/layout_widget"
        android:updatePeriodMillis="50000"
        android:resizeMode="horizontal|vertical"
        android:widgetCategory="home_screen"> 
        
    </appwidget-provider>
    

    针对上述文件中的配置信息来做下介绍。

    • minHeight、minWidth 定义Widget的最小高度和最小宽度(Widget可以通过拉伸来调整尺寸大小)。
    • previewImage 定义添加小部件时显示的图标。
    • initialLayout 定义了小部件使用的布局。
    • ***updatePeriodMillis***定义小部件自动更新的周期,单位为毫秒。
    • resizeMode 指定了 widget 的调整尺寸的规则。可取的值有: “horizontal”, “vertical”, “none”。“horizontal"意味着widget可以水平拉伸,“vertical”意味着widget可以竖值拉伸,“none”意味着widget不能拉伸;默认值是"none”。
    • widgetCategory 指定了 widget 能显示的地方:能否显示在 home Screen 或 lock screen 或 两者都可以。它的取值包括:“home_screen” 和 “keyguard”。Android 4.2 引入。
      最后,需要我们在AndroidManifest中注册AppWidgetProvider时引用该文件,使用如下:
    <receiver android:name=".widget.ListWidgetProvider">
         ...
        <meta-data
            android:name="android.appwidget.provider"
            android:resource="@xml/widget_provider" />
    </receiver>
    

    三.了解AppWidgetProvider类

    我们来简单了解下AppWidgetProvider这个类。Widget的功能均是通过AppWidgetProvider来实现的。我们跟进源码可以发现它是继承自BroadcastReceiver类,也就是一个广播接收者。上面我们提到过RemoteViews是运行在SystemServer进程中的,再结合此处我们应该可以推测小部件的事件应该是通过广播来实现的。像小部件的添加、删除、更新、启用、禁用等均是在AppWidgetProvider中通过接受广播来完成的。看AppWidgetProvider中的几个方法:

    • onUpdate() 当Widget被添加或者被更新时会调用该方法。上边我们提到通过配置updatePeriodMillis可以定期更新Widget。但是当我们在widget的配置文件中声明了android:configure的时候,添加Widget时则不会调用onUpdate方法。
    • onEnable() 这个方法会在用户首次添加Widget时调用。
    • onAppWidgetOptionsChanged() 这个方法会在添加Widget或者改变Widget的大小时候被调用。在这个方法中我们还可以根据Widget的大小来选择性的显示或隐藏某些控件。
    • onDeleted(Context, int[]) 当控件被删除的时候调用该方法
    • onEnabled(Context) 当第一个Widget被添加的时候调用。如果用户添加了两个这个小部件,那么只有第一个添加时才会调用onEnabled.
    • onDisabled(Context) 当最后一个Widget实例被移除的时候调用这个方法。在这个方法中我们可以做一些清除工作,例如删掉临时的数据库等。
    • onReceive(Context, Intent) 当接收到广播的时候会被调用。

    上述方法中,我们需要着重关心一下onUpdate()方法和onReceive()方法。因为onUpdate()方法会在Widget被添加时候调用,我们可以在此时为Widget添加一View的些交互事件,例如点击事件。由于本篇我们要实现的是一个列表小部件。因此我们还需要RemoteViewsFactory这个类来适配列表数据。

    先来看下ListWidgetProvider这个类中的代码:

    public class ListWidgetProvider extends AppWidgetProvider {
    
        private static final String TAG = "WIDGET";
    
        public static final String REFRESH_WIDGET = "com.oitsme.REFRESH_WIDGET";
        public static final String COLLECTION_VIEW_ACTION = "com.oitsme.COLLECTION_VIEW_ACTION";
        public static final String COLLECTION_VIEW_EXTRA = "com.oitsme.COLLECTION_VIEW_EXTRA";
        private static Handler mHandler=new Handler();
        private Runnable runnable=new Runnable() {
            @Override
            public void run() {
                hideLoading(Utils.getContext());
                Toast.makeText(Utils.getContext(), "刷新成功", Toast.LENGTH_SHORT).show();
            }
        };
    
        @Override
        public void onUpdate(Context context, AppWidgetManager appWidgetManager,
                             int[] appWidgetIds) {
    
            Log.d(TAG, "ListWidgetProvider onUpdate");
            for (int appWidgetId : appWidgetIds) {
                // 获取AppWidget对应的视图
                RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.layout_widget);
    
                // 设置响应 “按钮(bt_refresh)” 的intent
                Intent btIntent = new Intent().setAction(REFRESH_WIDGET);
                PendingIntent btPendingIntent = PendingIntent.getBroadcast(context, 0, btIntent, PendingIntent.FLAG_UPDATE_CURRENT);
                remoteViews.setOnClickPendingIntent(R.id.tv_refresh, btPendingIntent);
    
                // 设置 “ListView” 的adapter。
                // (01) intent: 对应启动 ListWidgetService(RemoteViewsService) 的intent
                // (02) setRemoteAdapter: 设置 gridview的适配器
                //    通过setRemoteAdapter将ListView和ListWidgetService关联起来,
                //    以达到通过 ListWidgetService 更新 ListView的目的
                Intent serviceIntent = new Intent(context, ListWidgetService.class);
                remoteViews.setRemoteAdapter(R.id.lv_device, serviceIntent);
    
    
                // 设置响应 “ListView” 的intent模板
                // 说明:“集合控件(如GridView、ListView、StackView等)”中包含很多子元素,如GridView包含很多格子。
                //     它们不能像普通的按钮一样通过 setOnClickPendingIntent 设置点击事件,必须先通过两步。
                //        (01) 通过 setPendingIntentTemplate 设置 “intent模板”,这是比不可少的!
                //        (02) 然后在处理该“集合控件”的RemoteViewsFactory类的getViewAt()接口中 通过 setOnClickFillInIntent 设置“集合控件的某一项的数据”
                Intent gridIntent = new Intent();
    
                gridIntent.setAction(COLLECTION_VIEW_ACTION);
                gridIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
                PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, gridIntent, PendingIntent.FLAG_UPDATE_CURRENT);
                // 设置intent模板
                remoteViews.setPendingIntentTemplate(R.id.lv_device, pendingIntent);
                // 调用集合管理器对集合进行更新
                appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
            }
            super.onUpdate(context, appWidgetManager, appWidgetIds);
        }
    
    
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
            if (action.equals(COLLECTION_VIEW_ACTION)) {
                // 接受“ListView”的点击事件的广播
                int type = intent.getIntExtra("Type", 0);
                int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                        AppWidgetManager.INVALID_APPWIDGET_ID);
                int index = intent.getIntExtra(COLLECTION_VIEW_EXTRA, 0);
                switch (type) {
                    case 0:
                        Toast.makeText(context, "item" + index, Toast.LENGTH_SHORT).show();
                        break;
                    case 1:
                        Toast.makeText(context, "lock"+index, Toast.LENGTH_SHORT).show();
                        break;
                    case 2:
                        Toast.makeText(context, "unlock"+index, Toast.LENGTH_SHORT).show();
                        break;
                }
            } else if (action.equals(REFRESH_WIDGET)) {
                // 接受“bt_refresh”的点击事件的广播
                Toast.makeText(context, "刷新...", Toast.LENGTH_SHORT).show();
                final AppWidgetManager mgr = AppWidgetManager.getInstance(context);
                final ComponentName cn = new ComponentName(context,ListWidgetProvider.class);
                ListRemoteViewsFactory.refresh();
                mgr.notifyAppWidgetViewDataChanged(mgr.getAppWidgetIds(cn),R.id.lv_device);
                mHandler.postDelayed(runnable,2000);
                showLoading(context);
            }
            super.onReceive(context, intent);
        }
    
        /**
         * 显示加载loading
         *
         */
        private void showLoading(Context context) {
            RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.layout_widget);
            remoteViews.setViewVisibility(R.id.tv_refresh, View.VISIBLE);
            remoteViews.setViewVisibility(R.id.progress_bar, View.VISIBLE);
            remoteViews.setTextViewText(R.id.tv_refresh, "正在刷新...");
            refreshWidget(context, remoteViews, false);
        }
    
        /**
         * 隐藏加载loading
         */
        private void hideLoading(Context context) {
            RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.layout_widget);
            remoteViews.setViewVisibility(R.id.progress_bar, View.GONE);
            remoteViews.setTextViewText(R.id.tv_refresh, "刷新");
            refreshWidget(context, remoteViews, false);
        }
    
    
    
        /**
         * 刷新Widget
         */
        private void refreshWidget(Context context, RemoteViews remoteViews, boolean refreshList) {
            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
            ComponentName componentName = new ComponentName(context, ListWidgetProvider.class);
            appWidgetManager.updateAppWidget(componentName, remoteViews);
            if (refreshList)
                appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetManager.getAppWidgetIds(componentName), R.id.lv_device);
        }
    }
    

    针对以上代码,我们着重来看onUpdate()方法。在onUpdate()中我们主要实现了两个功能,第一个功能ListView以外的事件点击,例如点击“刷新”来更新小部件。第二个功能是适配ListView并实现ListView内部Item控件的点击事件。在这个方法中我们首先获取到了一个RemoteView的实例,这个RemoteView对应的就是我们Widget布局的View。关于点击事件的实现代码中注释写的也比较详细,在这里就不做过多解释了。重点是需要了解如何实现并适配ListView,具体实现请看下节。

    四.RemoteViewsFactory实现列表适配

    上面我们提到了RemoteViewsFactory,这个类其实可以类比为ListView的Adapter,该类存在的意义就是为了适配ListView的数据。只不过这里是把Adapter换成RemoteViews来实现的。看下ListRemoteViewsFactory中的代码:

    class ListRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
        private final static String TAG="Widget";
        private Context mContext;
        private int mAppWidgetId;
    
        private static List<Device> mDevices;
    
        /**
         * 构造GridRemoteViewsFactory
         */
        public ListRemoteViewsFactory(Context context, Intent intent) {
            mContext = context;
            mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                    AppWidgetManager.INVALID_APPWIDGET_ID);
        }
    
        @Override
        public RemoteViews getViewAt(int position) {
            //  HashMap<String, Object> map;
    
            // 获取 item_widget_device.xml 对应的RemoteViews
            RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.item_widget_device);
    
            // 设置 第position位的“视图”的数据
            Device device = mDevices.get(position);
            //  rv.setImageViewResource(R.id.iv_lock, ((Integer) map.get(IMAGE_ITEM)).intValue());
            rv.setTextViewText(R.id.tv_name, device.getName());
    
            // 设置 第position位的“视图”对应的响应事件
            Intent fillInIntent = new Intent();
            fillInIntent.putExtra("Type", 0);
            fillInIntent.putExtra(ListWidgetProvider.COLLECTION_VIEW_EXTRA, position);
            rv.setOnClickFillInIntent(R.id.rl_widget_device, fillInIntent);
    
    
            Intent lockIntent = new Intent();
            lockIntent.putExtra(ListWidgetProvider.COLLECTION_VIEW_EXTRA, position);
            lockIntent.putExtra("Type", 1);
            rv.setOnClickFillInIntent(R.id.iv_lock, lockIntent);
    
            Intent unlockIntent = new Intent();
            unlockIntent.putExtra("Type", 2);
            unlockIntent.putExtra(ListWidgetProvider.COLLECTION_VIEW_EXTRA, position);
            rv.setOnClickFillInIntent(R.id.iv_unlock, unlockIntent);
    
            return rv;
        }
    
    
        /**
         * 初始化ListView的数据
         */
        private void initListViewData() {
            mDevices = new ArrayList<>();
            mDevices.add(new Device("Hello", 0));
            mDevices.add(new Device("Oitsme", 1));
            mDevices.add(new Device("Hi", 0));
            mDevices.add(new Device("Hey", 1));
        }
        private static int i;
        public static void refresh(){
            i++;
            mDevices.add(new Device("Refresh"+i, 1));
        }
    
        @Override
        public void onCreate() {
            Log.e(TAG,"onCreate");
            // 初始化“集合视图”中的数据
            initListViewData();
        }
    
        @Override
        public int getCount() {
            // 返回“集合视图”中的数据的总数
            return mDevices.size();
        }
    
        @Override
        public long getItemId(int position) {
            // 返回当前项在“集合视图”中的位置
            return position;
        }
    
        @Override
        public RemoteViews getLoadingView() {
            return null;
        }
    
        @Override
        public int getViewTypeCount() {
            // 只有一类 ListView
            return 1;
        }
    
        @Override
        public boolean hasStableIds() {
            return true;
        }
    
        @Override
        public void onDataSetChanged() {
        }
    
        @Override
        public void onDestroy() {
            mDevices.clear();
        }
    }
    

    有了RemoteViewsFactory 还需要有RemoteViewsService才能与ListView关联起来。来看RemoteViewsService的实现类ListWidgetService,很简单,只重写了onGetViewFactory方法:

    public class ListWidgetService extends RemoteViewsService {
    
        @Override
        public RemoteViewsService.RemoteViewsFactory onGetViewFactory(Intent intent) {
            return new ListRemoteViewsFactory(this, intent);
        }
    }
    

    至此我们可以再次回到ListWidgetProvider中的onUpdate()方法,来看ListWidgetService 是如何与ListView关联到一起的了。

     //  设置 “ListView” 的adapter。
     // (01) intent: 对应启动 ListWidgetService(RemoteViewsService) 的intent
     // (02) setRemoteAdapter: 设置 ListView的适配器
     //  通过setRemoteAdapter将ListView和ListWidgetService关联起来,
     //  以达到通过 ListWidgetService 更新 ListView 的目的
      Intent serviceIntent = new Intent(context, ListWidgetService.class);
      remoteViews.setRemoteAdapter(R.id.lv_device, serviceIntent);
    

    五.点击事件处理

    Widget中事件点击以及适配ListView,想必大家都有所了解了。那么对于事件的处理我们还没有提到,例如在Widget中点击了刷新后我们不能像在App中那样给控件设置一个事件监听来在回掉方法中处理。在文章开头我们就提到了Widget是依赖广播来实现,因此我们点击了刷新后其实仅仅是发送出来一个广播。如果我们不去处理广播那么点击事件其实是没有任何意义的。因此,来看ListWidgetProvider中第二个比较重要的方法onReceive()。这个方法比较简单,只要我们对特定的广播来做相应的处理就可以了。

    @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    	        if (action.equals(COLLECTION_VIEW_ACTION)) {//处理列表中的事件
                // 接受“ListView”的点击事件的广播
                int type = intent.getIntExtra("Type", 0);
                int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                        AppWidgetManager.INVALID_APPWIDGET_ID);
                int index = intent.getIntExtra(COLLECTION_VIEW_EXTRA, 0);
                switch (type) {
                    case 0:
                        Toast.makeText(context, "item" + index, Toast.LENGTH_SHORT).show();
                        break;
                    case 1:
                        Toast.makeText(context, "lock"+index, Toast.LENGTH_SHORT).show();
                        break;
                    case 2:
                        Toast.makeText(context, "unlock"+index, Toast.LENGTH_SHORT).show();
                        break;
                }
            } else if (action.equals(REFRESH_WIDGET)) {//处理刷新事件
                // 接受“bt_refresh”的点击事件的广播
                Toast.makeText(context, "刷新...", Toast.LENGTH_SHORT).show();
                final AppWidgetManager mgr = AppWidgetManager.getInstance(context);
                final ComponentName cn = new ComponentName(context,ListWidgetProvider.class);
                ListRemoteViewsFactory.refresh();
                mgr.notifyAppWidgetViewDataChanged(mgr.getAppWidgetIds(cn),R.id.lv_device);
                mHandler.postDelayed(runnable,2000);
                showLoading(context);
            }
            super.onReceive(context, intent);
        }
    

    最后,别忘了ListWidgetProvider是广播,ListWidgetService是服务,都需要我们在AndroidManifest文件中来注册:

    	   <receiver android:name=".widget.ListWidgetProvider">
                <intent-filter>
                    <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    
                    <!-- ListWidgetProvider接收点击ListView的响应事件 -->
                    <action android:name="com.oitsme.COLLECTION_VIEW_ACTION" />
                    <!-- ListWidgetProvider接收点击bt_refresh的响应事件 -->
                    <action android:name="com.oitsme.REFRESH_WIDGET" />
                    <action android:name="com.oitsme.LOCK_ACTION"/>
                    <action android:name="com.oitsme.UNLOCK_ACTION"/>
                </intent-filter>
                <meta-data android:name="android.appwidget.provider"
                    android:resource="@xml/widget_provider"/>
            </receiver>
    
            <service
                android:name=".widget.ListWidgetService"
                android:permission="android.permission.BIND_REMOTEVIEWS" />
    

    六.小结

    至此关于列表小部件的讲解就完成了。只是自我感觉文章的逻辑有点乱。如果没明白,大家可以参考下面Demo源码。其实关于Widget的这个Demo其实早在几个月前就已经写好了,但由于最近项目紧再加上本身也是第一次接触Widget控件,因此直至近日才开始动笔写这篇文章。所以文章中避免不了有错误和不合理的地方,欢迎留言指正。

    参考
    https://developer.android.com/guide/topics/appwidgets/

    源码下载

    开源库推荐

    BannerViewPager

    一个基于ViewPager2实现的具有强大功能的无限轮播库。支持多种页面切换效果和指示器样式。

    ViewPagerIndicator

    一个适用于ViewPager和ViewPager2的指示器,支持多种滑块样式及滑动模式

    展开全文
  • ios Widget

    2018-05-21 13:52:31
    自iOS8之后,苹果支持了扩展(Extension)的开发,开发者可以通过系统提供给我们的扩展接入点 (Extension point) 来为...今年iOS10的推出,让Widget扩展应用渐渐的火了起来,地位得到重大的提升,从这也可以...
    转载:https://www.jianshu.com/p/012319813522
    

    自iOS8之后,苹果支持了扩展(Extension)的开发,开发者可以通过系统提供给我们的扩展接入点 (Extension point) 来为系统特定的服务提供某些附加的功能。今年iOS10的推出,让Widget扩展应用渐渐的火了起来,地位得到重大的提升,从这也可以看出苹果对他的重视,今天我们就来一起学习下Widget,来实现一个简单的扩展程序。

    iOS Widget扩展程序

    程序效果

    程序效果图

    创建Widget程序

    • 创建工程,在工程中添加扩展程序
    创建Widget程序
    • 创建成功后的目录
    创建成功

    顺便说一句,扩展程序虽然是程序的扩展,但是这两个应用其实是“独立”的。准确的来说,它们是两个独立的进程,默认情况下互相不应该知道对方的存在。扩展需要对宿主 app (host app,即调用该扩展的 app) 的请求做出响应,当然,通过进行配置和一些手段,我们可以在扩展中访问和共享一些容器 app 的资源,这个我们稍后再说。

    Widget布局方式

    • 使用Interface Builder
      工程默认的方式就是使用Interface Builder,如果实现简单的布局的话可以考虑这种方式。
    • 使用代码进行布局
      当涉及到比较复杂的UI布局的时候,可以考虑使用这种布局方式,按大家平时的习惯来。这里需要注意一下,如果需要使用代码布局的话需要修改一下plist文件。
      首先将原有NSExtensionMainStoryboard字段删除,添加字段NSExtensionPrincipalClass,value是你所写的controller的名称,一般默认的都是TodayViewController
    修改plist文件

    实现相应的方法

    1. 设置Widget的size
    iOS10之后,Widget支持展开及折叠两种展现方式,通过设置widgetLargestAvailableDisplayMode属性可以让Widget程序实现展开布局。如下:

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view from its nib.
    
        if (isIOS10)
        {
            self.extensionContext.widgetLargestAvailableDisplayMode = NCWidgetDisplayModeExpanded;
        }
    
        self.preferredContentSize = CGSizeMake(kWidgetWidth, 110);
    }
    

    2. 重写切换展开及折叠布局时的方法(iOS10之后)

    - (void)widgetActiveDisplayModeDidChange:(NCWidgetDisplayMode)activeDisplayMode withMaximumSize:(CGSize)maxSize
    {
        NSLog(@"maxWidth %f maxHeight %f",maxSize.width,maxSize.height);
    
        if (activeDisplayMode == NCWidgetDisplayModeCompact)
        {
            self.preferredContentSize = CGSizeMake(maxSize.width, 110);
        }
        else
        {
            self.preferredContentSize = CGSizeMake(maxSize.width, 200);
        }
    }
    

    3. iOS10之前,视图原点默认存在一个间距,可以实现以下方法来调整视图间距
    注:该方法在iOS10之后被遗弃,iOS10默认不存在间距。

    - (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets
    {
        return UIEdgeInsetsMake(0, 10, 0, 10);
    }
    

    应用唤醒

    本来想叫应用间跳转的,想想还是这个名字比较高大上些��
    如下,配置url scheme,这个定义的时候尽量不要和其他用用冲突,笔者定义的为WidgetDemo。这样,通过访问WidgetDemo://就可以实现应用唤醒了。代码如下:

    配置url scheme
    - (void)redButtonPressed:(UIButton *)button
    {
        NSLog(@"%s",__func__);
    
        NSURL *url = [NSURL URLWithString:@"WidgetDemo://red"];
    
        [self.extensionContext openURL:url completionHandler:^(BOOL success) {
    
            NSLog(@"isSuccessed %d",success);
        }];
    }
    

    相应的,在AppDelegate中实现以下方法,这里可以处理传过来的action,对于传过来不同的值可以进行不同的操作,这里我们打印了请求url的内容。

    - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
    {
        if ([[url absoluteString] hasPrefix:@"WidgetDemo"])
        {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:[NSString stringWithFormat:@"你点击了%@按钮",[url host]] delegate:nil cancelButtonTitle:@"好的��" otherButtonTitles:nil, nil];
            [alert show];
        }
        return  YES;
    }
    
    • 简易的应用快速启动器
      既然说到了应用唤醒,这里再稍稍拓展以下,想必大家都有用过类似launcher这种的应用快速启动器。其实就是运用了应用间跳转的原理,每款应用都有自定义的url scheme,我们只要知道他们的url scheme就可以跳转至改款应用,例如进行微信的跳转:
    - (void)wechatLoginButtonPressed
    {
        NSLog(@"%s",__func__);
    
        NSURL *url = [NSURL URLWithString:@"wechat://"];
    
        [self.extensionContext openURL:url completionHandler:^(BOOL success) {
    
            NSLog(@"isSuccessed %d",success);
        }];
    }
    

    以下是我们比较常用的软件的url scheme,有兴趣的同学们可以试一试:
    QQ mqq:// 微信 weixin:// 淘宝taobao:// 微博 sinaweibo:// 支付宝alipay://

    数据共享

    扩展程序一般都不是脱离宿主程序单独运行的,难免需要和宿主程序进行数据交互。而相对于一般的APP,数据可以用单例,NSUserDefault等等。但由于拓展与宿主应用是两个完全独立的App,并且iOS应用基于沙盒的形式限制,所以一般的共享数据方法都是实现不了数据共享,这里就需要使用App Groups。

    • 在宿主程序和扩展程序中分别设置打开App Group,设置一个group的名称,这里要保证宿主APP和扩展APP的groupName要是相同的。
    设置App Group

    两种数据存储方式

    • 使用NSUserDefault
      这里不能使用[NSUserDefaults standardUserDefaults];方法来初始化NSUserDefault对象,正像之前所说,由于沙盒机制,拓展应用是不允许访问宿主应用的沙盒路径的,因此上述用法是不对的,需要搭配app group完成实例化UserDefaults。正确的使用方式如下:
      写入数据
        NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.japho.widgetDemo"];
        [userDefaults setObject:self.textField.text forKey:@"widget"];
        [userDefaults synchronize];
    

    读取数据

        NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.japho.widgetDemo"];
        self.contentStr = [userDefaults objectForKey:@"widget"];
    
    • 通过NSFileManager共享数据
      写入数据
    -(BOOL)saveDataByNSFileManager
    {
        NSError *err = nil;
        NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.xxx"];
        containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/ widget"];
        NSString *value = @"asdfasdfasf";
        BOOL result = [value writeToURL:containerURL atomically:YES encoding:NSUTF8StringEncoding error:&err];
        if (!result)
        {
            NSLog(@"%@",err);
        }
        else
        {
            NSLog(@"save value:%@ success.",value);
        }
        return result;
    }
    

    读取数据

    -(NSString *)readDataByNSFileManager
    {
        NSError *err = nil;
        NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.com.xxx"];
        containerURL = [containerURL URLByAppendingPathComponent:@"Library/Caches/ widget"];
        NSString *value = [NSString stringWithContentsOfURL:containerURL encoding: NSUTF8StringEncoding error:&err];
        return value;
    }
    

    其他

    补充:widget的上线也是需要单独申请APP ID的 需要配置证书和Provisioning Profiles文件
    没有配置相关证书时:



    配置证书及描述文件:(列举一些)




    证书与描述文件配置好之后:
    展开全文
  • Widget的简单使用详解

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

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

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

    万次阅读 2018-08-11 19:43:30
    QWidget 详解内容 - 两种常用的几何结构 不包含边框的常用函数 包含边框的常用函数 实例 :一屏幕坐标系统显示 实例二:设置程序图标 实例三:显示气泡提示信息 ... 这两个函数改变了...
  • AppWidget:基本使用

    千次阅读 2017-03-21 17:42:27
    App Widget是应用程序窗口小部件(Widget)是微型的应用程序视图,它可以被嵌入到其它应用程序中(比如桌面)并接收周期性的更新。你可以通过一个App Widget Provider来发布一个Widget。 本文参考Android官方文本,...
  • 这几天做桌面widget,现将所涉及内容整理分享给大家。写博客时间长了,觉得只是把学到的知识写出来才算是已经学会了的。这也算是强迫症了吧。今天头有点痛,心情不太好,就不多请废话了,估计也没几个人会看我的前言...
  • Hexo添加Live2D看板娘+模型预览

    万次阅读 2019-02-13 15:02:19
    文章目录添加和注意事项模型预览live2d-widget-model-chitoselive2d-widget-model-epsilon2_1live2d-widget-model-gflive2d-widget-model-haru_01live2d-widget-model-haru_02live2d-widget-model-harutolive2d-...
  • QT设置centralWidget布局

    万次阅读 2017-11-20 17:22:19
    QT设置centralWidget布局设置之前是这样的,这时候即使设置了控件的布局,实际上控件大小还是不会跟这变,因为centralWidget没有设置布局。 需要在没有控件的空白区域,点击右键在布局中选择一种布局: 布局后...
  • assertion ‘GTK_IS_WIDGET (widget)’ failed的解决办法 Linux系统下GTK+ 利用Glade界面设计过程中出现问题编译后执行出现下面错误:gcc -o demoglade demoglade.c `pkg-config --cflags --libs gtk+-2.0` ...
  • android.support.v7.widget包找不到

    万次阅读 热门讨论 2019-12-30 16:34:42
    import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGrid....
  • 很简单,在Qtdesigner中对象查看器里选中名为centarlWidget部件,然后在工具栏中点击想要的layout,即可将centralWidget转换为对应的布局Layout,这样,在这个layout里面的部件即可随着整个窗口(Widget)的大小变化...
  • 在ListWidget中添加自定义的Item

    万次阅读 2016-09-02 16:50:16
    之前看过很多在ListWidget中添加item的方法,但是大部分都没能解决我的问题。 昨天把这个问题解决了,想着把它记下来。留个纪念吧。 先上一个图例。 就像这一样。这个是纯代码实现。以下是纯代码 #...
  • 比如墨迹天气有4x1,5x1,4x2等等大小,这个是怎么搞出来的呢??
  • QListWidget和QListWidgetItem的简单使用

    万次阅读 2009-12-02 11:40:00
    QListWidget可以显示一个清单,清单中的每个项目是QListWidgetItem的一个实例,每个项目可以通过QListWidgetItem来操作。可以通过QListWidgetItem来设置每个项目的图像与文字。下面说明3个例子,一个例子只显示文字...
  • Qt工作笔记-使用信号与槽让两个界面进行数据通信

    千次阅读 热门讨论 2018-03-27 22:50:11
    今天在项目中,发现有一个十分重要的功能,就是2个界面进行数据...功能如下动态图:这里的逻辑是Widget类是主界面,他构造出一个主界面。Widget2类是当Widget里面点击按钮才创建的界面,Widget2把输入的数据发送给Wi...
  • Eclipse出现Widget is disposed错误

    千次阅读 2017-10-10 19:10:19
    在Eclipse中切换正常磨损和Debug模式的时候出现了这种问题。 可以通过关闭toggle breakcrumb。来屏蔽这种错误。如图所示:
1 2 3 4 5 ... 20
收藏数 370,674
精华内容 148,269
关键字:

widget