精华内容
下载资源
问答
  • show_widgets_example:通过在Flutter中展示最重要部件及其功能,向用户介绍您应用
  • 通过使用服务器做大量“苦力活儿”,我们可以我们最终用户提供更加平顺的用户体验。什么苦力活要交给服务器呢?假设你有一百万行数据集,这些数据要是发送到客户端,然后再进行排序/分页/过滤,那会是相当...

    在之前的一篇文章中,我们讨论了如何添加一大堆的超赞的功能到一个标准的HTML表,并把它转换成一个“grid”表格。今天我想要做的事情是向你展示如何将这些功能转到服务器。

    通过使用服务器做大量的“苦力活儿”,我们可以向我们的最终用户提供更加平顺的用户体验。什么苦力活要交给服务器呢?假设你有一百万行的数据集,这些数据要是发送到客户端,然后再进行排序/分页/过滤,那会是相当可观的一堆流量。但是如果我们要求服务器在发送数据到客户端之前执行排序/分页/过滤,我们可以迅速的减少客户端的开销。

     

    服务器

    关于数据,我使用Chinook数据库。它速度快,容易设置,同时可以给我的例子提供很好的数据。我在例子中使用到了ASP.NET MVC3,并且我们只实现排序和过滤。

    public JsonResult GetAlbumList()
    
    {
    
    int pageSize = Request.Params["paging[pageSize]"] != null ? Convert.ToInt32(Request.Params["paging[pageSize]"]) : 0;
    
    int pageIndex = Request.Params["paging[pageIndex]"] != null ? Convert.ToInt32(Request.Params["paging[pageIndex]"]) : 0;
    
    string sortColumn = Request.Params["sorting[0][dataKey]"];
    
    string sortDirection = Request.Params["sorting[0][sortDirection]"];
    
    if (string.IsNullOrEmpty(sortColumn)) sortColumn = String.Empty;
    
    if (string.IsNullOrEmpty(sortDirection)) sortDirection = String.Empty;
    
    using (var entity = new ChinookEntities())
    
    {
    
    var allAlbums = from al in entity.Albums
    
    join ar in entity.Artists on al.ArtistId equals ar.ArtistId
    
    select new AlbumResult()
    
    {
    
    AlbumName = al.Title,
    
    ArtistName = ar.Name
    
    };
    
    var totalRowCount = allAlbums.Count();
    
    if (pageSize == 0)
    
    pageSize = totalRowCount;
    
    if (sortColumn.ToLower() != "album")
    
    allAlbums = sortDirection.ToLower() == "descending"
    
    ? allAlbums.OrderByDescending(p => p.ArtistName).Skip(pageSize*pageIndex).Take(pageSize)
    
    : allAlbums.OrderBy(p => p.ArtistName).Skip(pageSize*pageIndex).Take(pageSize);
    
    else
    
    allAlbums = sortDirection.ToLower() == "descending"
    
    ? allAlbums.OrderByDescending(p => p.AlbumName).Skip(pageSize*pageIndex).Take(pageSize)
    
    : allAlbums.OrderBy(p => p.AlbumName).Skip(pageSize*pageIndex).Take(pageSize);
    
    var result = new WijmoGridResult { Items = allAlbums.ToList(), TotalRowCount = totalRowCount };
    
    return Json(result, JsonRequestBehavior.AllowGet);
    
    }
    
    }

     

     

    让我们一行一行的看一看这些代码都作了些什么,因为他确实做了很多事情!最初的六行抽取了Wijmo需要发送的Request参数。因为很有可能这些值为空,一点点的参数检查逻辑是必须的。

    从using表达式开始,我们使用Entity Framework打开一个到我们数据库的链接。我们使用延迟加载的想法对创建结构化查询,因此和SQL服务器的交互只有一次。第一次查询创建对数据库中所有相册的查询。获取所有行的个数是必须的。Wijmo会使用这个结果判断分页需求。

    关于排序,你也许已经被巨复杂的IF..ELSE表达式折磨得疲惫不堪。所有这些逻辑仅仅是为了判断我们要基于哪一列进行排序以及按照何种方式(升序或者降序)进行排列,同时应用LINQ过滤。这些调用同时也使用了Skip()以及Take()技术进行分页。

    最后,你可能注意到了我还没有给出AlbumReult以及WijmoGridResult的定义。以下是这些类的代码:

    public class AlbumResult
    
    {
    
    public string AlbumName { get; set; }
    
    public string ArtistName { get; set; }
    
    }
    
    public class WijmoGridResult
    
    {
    
    public List Items { get; set; }
    
    public int TotalRowCount { get; set; }
    
    }

     

     

    客户端

    现在服务器端已经配置好了,我们需要改变一点Wijmo的配置以以便使用这些新设置。

    $(document).ready(function () {
    
    var dataReader = new wijarrayreader([
    
    { name: "Artist", mapping: "ArtistName" },
    
    { name: "Album", mapping: "AlbumName" }
    
    ]);
    
    var dataSource = new wijdatasource({
    
    proxy: new wijhttpproxy({
    
    url: "@Url.Action("GetAlbumList")",
    
    dataType: "json"
    
    }),
    
    dynamic: true,
    
    reader: {
    
    read: function (datasource) {
    
    var count = datasource.data.TotalRowCount;
    
    datasource.data = datasource.data.Items;
    
    datasource.data.totalRows = count;
    
    dataReader.read(datasource);
    
    }
    
    }
    
    });
    
    $("#remoteTable").wijgrid({
    
    pageSize: 15,
    
    data: dataSource,
    
    allowPaging: true,
    
    allowSorting: true
    
    });
    
    });

     

     

    在最开始,我们打算声明一个新的datareader,用来读取来自服务器的JSON数据。它将告诉Wijmo如何将JSON属性映射到表格的列。

    接下来是数据源。这是一个URL的代理。Wijmo会在这个URL上做一个GET操作以获取信息。这里dynamic关键字告诉Wijmo,服务器会接受排序,过滤以及分页请求。如果它被设置为false或者从来都没有设置过,Wijmo不会发送我们之前提到的请求参数。Reader告诉Wijmo如何解释数据,并且获取行数,之后是应用darareader。

     

    最后一个调用是真正的创建WijGrid。这和你之前曾经看过的没有什么不同。唯一使得服务器收集数据的设置就是datasource。

    展开全文
  • 在这个由两部分组成系列文章中,我将展示如何通过Android项目中添加应用程序小部件来提供更好的用户体验。 在本系列最后,您将创建一个小部件,该小部件: 显示多组数据。 当用户与该小部件的布局...

    从Android 1.5开始,应用程序小部件使用户能够在舒适的主屏幕上获取信息,控制应用程序并执行关键任务。

    在这个由两部分组成的系列文章中,我将向您展示如何通过向Android项目中添加应用程序小部件来提供更好的用户体验。

    在本系列的最后,您将创建一个小部件,该小部件:

    • 显示多组数据。
    • 当用户与该小部件的布局内的特定View交互时,执行唯一的操作。
    • 在设定的时间段过后会自动更新。
    • 更新新数据以响应用户交互。

    在第一篇文章中,我们将使用Android Studio的内置工具快速轻松地生成交付任何 Android应用程序小部件所需的所有文件。 然后,我们将在此基础上扩展以创建一个小部件,该小部件可检索和显示数据并响应onClick事件。

    什么是应用程序小部件?

    应用程序小部件是轻量级的微型应用程序,通常属于以下类别之一:

    • 信息小部件。 显示重要信息的不可滚动小部件,例如天气或时钟小部件。
    • 集合小部件。 可滚动的窗口小部件,显示一系列相关元素,例如来自同一出版物的照片画廊或文章画廊。 集合小部件通常由数据源(例如Array或数据库)支持。 集合小部件必须包含ListViewGridViewStackViewAdapterViewFlipper
    • 控制小部件。 一个小部件,可充当您的应用程序的远程控件,使用户无需启动您的应用程序即可触发常用功能。 播放音乐的应用程序通常会提供一个小部件,使用户可以直接从其主屏幕播放,暂停和跳过曲目。
    • 混合小部件。 当您可以从多个类别中挑选元素时,为什么将自己限制在一个类别中? 请注意,混合和匹配会导致混乱的用户体验,因此为了获得最佳效果,您应该在设计widget时考虑单个类别,然后根据需要添加其他类别的元素。 例如,如果您想要创建一个小部件以显示今天的天气预报,但还允许用户查看不同日期和位置的天气预报,则您应该创建一个信息小部件,然后再添加必要的控制元素。

    除了上述功能之外,大多数小部件都通过启动其关联的应用程序来响应onClick事件,类似于应用程序快捷方式,但它们也可以提供对该应用程序中特定内容的直接访问。

    尽管有一些第三方App Widget Host,例如流行的Nova LauncherApex Launcher ,但应用Widget必须放置在App Widget Host (最常见的是Android主屏幕)中。

    在整个系列中,我将把小部件作为您放置在主屏幕上的方式进行讨论,但是如果您对能够将小部件放置在锁屏上的想法有所含糊,那么这不仅仅是一个美好的梦想! API级别17和20之间,有可能将小部件在主屏幕或锁屏。

    由于锁屏窗口小部件在API级别21中已弃用,因此在本系列中,我们将仅为主屏幕创建窗口小部件。

    为什么要创建应用程序小部件?

    有几个原因让您考虑将应用程序小部件添加到最新的Android项目中。

    轻松访问重要信息和功能

    窗口小部件允许用户直接从其主屏幕查看应用程序的最重要信息。 例如,如果您开发了日历应用程序,则可以创建一个小部件,以显示有关用户的下一个约会的详细信息。 这比强迫用户启动您的应用程序并可能浏览多个屏幕来检索相同的信息要方便得多。

    如果您开发控件控件(或带有控件元素的混合控件),则用户还可以直接从其主屏幕完成任务。 继续我们的日历示例,您的小部件可能允许用户创建,编辑和取消约会,甚至不必启动您的应用程序。 这有可能从您的应用程序的一些最重要的任务中删除多个导航步骤,这只会对用户体验产生积极的影响!

    直接访问应用程序所有最重要的屏幕

    轻按窗口小部件通常会将用户带到关联应用程序的顶层,类似于应用程序快捷方式。 但是,与应用程序快捷方式不同,小部件可以链接到关联应用程序内的特定区域。 例如,点击小部件的“收到新电子邮件”通知可能会启动应用程序,并且已选择了新消息,而点击“ 创建新电子邮件”可能会将它们直接带到应用程序的ComposeEmail活动中。

    通过在窗口小部件的布局中嵌入多个链接,您可以一键式访问应用程序中所有最重要的活动。

    建立忠实的用户群

    正如整个Pokemon Go爆炸和随后的失败所证明的那样,吸引大量人下载您的应用程序并不能自动保证忠实的用户群仍会在几天,几周甚至几个月内使用您的应用程序。

    移动用户非常善变,随着典型Android智能手机或平板电脑上可用内存的不断增加,很容易丢失对设备上已安装应用程序的跟踪。 如果您现在拿起Android智能手机或平板电脑并在应用程序抽屉中滑动,则可能会发现至少一个您完全忘记的应用程序。

    通过创建一个小部件来展示您的应用程序所有最有价值的信息和功能,您可以确保每次用户浏览主屏幕时,不仅会提醒他们您的应用程序存在,而且还会提醒您该应用程序包含一些很棒的内容。

    将应用程序小部件添加到您的项目

    即使最基本的窗口小部件也需要多个类和资源,但是当您使用Android Studio的内置工具创建窗口小部件时,所有这些文件都是为您生成的。 由于没有必要使Android开发变得比原来更难,因此我们将使用这些工具来抢先构建小部件。

    应用程序小部件必须始终绑定到基础应用程序,因此请使用您选择的设置创建一个新的Android项目。

    Android Studio构建完项目后,请从Android Studio工具栏中选择文件>新建>窗口小部件> AppWidget 这将启动“ 配置组件”菜单,您可以在其中定义小部件的一些初始设置。

    在Android Studio中配置小部件设置

    这些选项大多数都是不言自明的,但是有一些值得更详细地探讨。

    可调整大小(API 12+)

    如果窗口小部件可调整大小,则用户可以通过长按窗口小部件然后拖动其轮廓周围的蓝色手柄来增加或减少其在主屏幕上占据的“单元格”数量。

    只要有可能,您都应该使小部件能够水平和垂直调整大小,因为这将帮助您的小部件适应各种屏幕配置和主屏幕设置。 如果用户的主屏幕非常混乱,那么除非您的小部件可调整大小,否则您的小部件可能甚至无法放入该主屏幕。

    如果你想创建一个非可调整大小的小部件,然后打开ResizablË下拉菜单,选择只水平只有垂直 ,或不调整大小

    最小宽度和高度

    最小宽度和高度指定将小部件放置在主屏幕上时最初占据的单元数。

    对于可调整大小的窗口小部件,这是用户可以调整窗口小部件尺寸的最小尺寸,因此您可以使用这些值来防止用户将窗口小部件缩小到无法使用的程度。

    如果您的窗口小部件不可调整大小,则最小宽度和高度值为窗口小部件的永久宽度和高度。

    为了增加窗口小部件在各种主屏幕上舒适安装的机会,建议您不要使用大于4乘4的最小宽度和高度值。

    尽管设备之间的主屏幕“单元”的确切宽度和高度会有所不同,但您可以使用以下公式大致估算小部件将占用多少DPI(每英寸点数):

    70 × number of cells -30

    例如,如果您的窗口小部件是2 x 3单元格:

    70 x 2 - 30 = 110
    70 x 3 - 30 = 180

    该小部件将在用户主屏幕上占用大约110 x 180 DPI。 如果这些值与特定设备的单元格尺寸不一致,则Android会自动将小部件舍入到最接近的单元格大小。

    查看此菜单中的所有选项,并进行所需的更改(我坚持使用默认值),然后单击完成

    Android Studio现在将生成交付基本应用程序小部件所需的所有文件和资源。 这个小部件并不是完全令人兴奋(它基本上只是一个蓝色的块,上面写有“ 示例 ”一词),但是它一个可以在设备上测试的功能小部件。

    要测试小部件:

    • 在物理Android设备或AVD(Android虚拟设备)上安装项目。
    • 启动Android的小部件选择器 通过按下主屏幕上的任何空白区域,然后点击出现在屏幕底部的“窗口小部件 ”一词。
    • 滑动小部件选择器,直到发现蓝色的示例小部件。
    • 按下此小部件以将其放到主屏幕上。
    • 按下小部件直到出现一组蓝色手柄,进入调整大小模式 ,然后拖动这些手柄以增加或减少此小部件占用的单元格数量。
    在Android虚拟设备上测试您的小部件

    探索应用程序小部件文件

    这个小部件可能不会很多事情,但是它包含了本系列其余部分将要使用的所有类和资源,因此让我们看一下这些文件及其在交付应用程序小部件中所扮演的角色。

    NewAppWidget.java

    窗口小部件提供程序是一个便利类,其中包含用于通过广播事件以编程方式与窗口小部件交互的方法。 实际上,小部件实际上只是可以响应各种动作的BroadcastReceiver ,例如用户将新的小部件实例放置在其主屏幕上。

    最值得注意的是,您可以在应用程序窗口小部件提供程序中定义窗口小部件的生命周期方法,该方法可以针对窗口小部件的每个实例或仅针对特定实例而调用。

    尽管我们倾向于将小部件视为用户在其主屏幕上放置一次的单个实体,但是没有什么可以阻止他们创建同一小部件​​的多个实例。 也许您的窗口小部件是可定制的,以至于不同的实例可能具有明显不同的功能,或者用户只是非常喜欢您的窗口小部件,以至于希望将其粘贴在整个主屏幕上!

    让我们看一下可以在窗口小部件提供程序类中实现的不同生命周期方法:

    onReceive事件

    每当发生指定事件时,Android都会在已注册的BroadcastReceiver上调用onReceive()方法。

    通常,您不需要手动实现此方法,因为AppWidgetProvider类会自动过滤所有小部件广播并将操作委托给适当的方法。

    onEnabled事件

    onEnabled()生命周期方法被调用响应ACTION_APPWIDGET_ENABLED ,当用户添加小工具的第一个实例,以他们的主屏幕被播出。 如果用户创建了窗口小部件的两个实例,则将为第一个实例调用onEnabled() ,而不是第二个实例。

    在这种生命周期方法中,您可以对所有窗口小部件实例执行只需要发生一次的任何设置,例如创建数据库或设置服务。

    请注意,如果用户从其设备上删除窗口小部件的所有实例,然后创建一个新实例,则该实例将被分类为第一个实例,因此将再次调用onEnabled()方法。

    onAppWidgetOptionsChanged事件

    响应于ACTION_APPWIDGET_OPTIONS_CHANGED调用此生命周期方法,该操作在创建窗口小部件实例时以及每次调整窗口小部件大小时广播。 您可以使用此方法根据用户调整窗口小部件的大小来显示或隐藏内容,尽管此回调仅在Android 4.1及更高版本中受支持。

    onUpdate事件

    每次调用onUpdate()生命周期方法:

    • 更新间隔已经过去。
    • 用户执行触发onUpdate()方法的操作。
    • 用户在其主屏幕上放置一个小部件的新实例(除非小部件包含配置活动,我们将在第二部分中介绍)。

    还响应于ACTION_APPWIDGET_RESTORED调用onUpdate()生命周期方法,每当从备份中恢复窗口小部件时都会广播该方法。

    对于大多数项目, onUpdate()方法将包含大量的窗口小部件提供程序代码,尤其是因为它也是您注册窗口小部件的事件处理程序的地方。

    onDeleted事件

    onDeleted()您的小部件实例从“应用小部件主机”中删除时,都会调用onDeleted()方法,这会触发系统的ACTION_APPWIDGET_DELETED广播。

    onDisabled事件

    响应于ACTION_APPWIDGET_DISABLED广播而调用此方法,该广播是在从应用程序小部件主机删除小部件的最后一个实例时发送的。 例如,如果用户创建了窗口小部件的三个实例,则仅当用户从其主屏幕中删除第三个也是最后一个实例时,才会调用onDisabled()方法。

    onDisabled()的生命周期方法,你应该清理你创建的任何资源onEnabled()所以如果你在建立一个数据库onEnabled()那么你就在删除onDisabled()

    onRestored事件

    所述onRestored()方法被调用响应于ACTION_APPWIDGET_RESTORED ,这是广播窗口小部件从备份中恢复应用程序的每当一个实例。 如果要维护任何持久性数据,则需要重写此方法,并将以前的AppWidgetIds重新映射到新值,例如:

    public void onRestored(Context context, int[] oldWidgetIds,
               int[] newWidgetIds) {
       }
    }

    如果您打开Android Studio自动生成的NewAppWidget.java文件,那么您将看到它已经包含以下某些窗口小部件生命周期方法的实现:

    import android.appwidget.AppWidgetManager;
    import android.appwidget.AppWidgetProvider;
    import android.content.Context;
    import android.widget.RemoteViews;
    
    //All widgets extend the AppWidgetProvider class//
    
    public class NewAppWidget extends AppWidgetProvider {
    
    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                                  int appWidgetId) {
    
          CharSequence widgetText = context.getString(R.string.appwidget_text);
    
        //Load the layout resource file into a RemoteViews object//
    
          RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
          views.setTextViewText(R.id.appwidget_text, widgetText);
    
     //Tell the AppWidgetManager about the updated RemoteViews object//
    
          appWidgetManager.updateAppWidget(appWidgetId, views);
      }
    
    //Define the onUpdate lifecycle method//
    
      @Override
      public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    
    //appWidgetIds is an array of IDs that identifies every instance of your widget, so this 
    //particular onUpdate() method will update all instances of our application widget//
    
          for (int appWidgetId : appWidgetIds) {
              updateAppWidget(context, appWidgetManager, appWidgetId);
          }
      }
    
      @Override
    
    //Define the onEnabled lifecycle method//
    
      public void onEnabled(Context context) {
          
          //To do//
      }
    
      @Override
    
    //Define the onDisabled method//
    
      public void onDisabled(Context context) {
          
    //To do//
    
      }
    }

    小部件布局文件

    res / layout / new_app_widget.xml文件定义了小部件的布局,当前它只是一个蓝色背景,上面写有示例

    为活动创建布局和为小部件创建布局之间的主要区别在于,小部件布局必须基于RemoteViews ,因为这使Android可以在应用程序外部的进程中(即,在用户的主屏幕上)显示布局。

    RemoteViews不支持每种布局或View ,因此在构建窗口小部件布局时,您只能使用以下类型:

    • AnalogClock
    • Button
    • Chromometer
    • FrameLayout
    • GridLayout
    • ImageButton
    • ImageView
    • LinearLayout
    • ProgressBar
    • RelativeLayout
    • TextView
    • ViewStub

    如果要创建集合窗口小部件,则在将应用程序安装在Android 3.0及更高版本上时,也可以使用以下类型:

    • AdapterViewFlipper
    • GridView
    • ListView
    • StackView
    • ViewFlipper

    不支持上述Views和类的子类和后代。

    点击和滑动

    为确保用户在主屏幕上浏览时不会意外与小部件交互,小部件仅响应onClick事件。

    例外是当用户通过将小部件拖向其主屏幕的“ 卸载”操作来删除它时,因为在这种情况下,您的小部件将响应垂直滑动手势。 但是,由于此交互是由Android系统管理的,因此您无需担心在应用程序中实现垂直滑动支持。

    小部件信息文件

    res / xml / new_app_widget_info.xml文件(也称为AppWidgetProviderInfo文件)定义了许多小部件属性,包括您在Android Studio的“ 配置组件”菜单中选择的许多设置,例如小部件的最小尺寸以及是否可以放置它在锁屏上。

    配置文件还指定您的窗口小部件从App窗口小部件更新服务请求新信息的频率。 确定此频率要求您达到一个棘手的平衡:较长的更新间隔将有助于节省设备的电池电量,但是将间隔间隔太远,则小部件可能会显示明显过时的信息。

    您还应该知道,系统将唤醒睡眠中的设备以检索新信息,因此尽管每半小时更新一次小部件听起来可能不算过多,但它可能会导致小部件每30分钟唤醒一次设备,即会影响电池消耗。

    如果打开项目的new_app_widget_info.xml文件,则将看到它已经定义了许多小部件属性,包括更新间隔。

    <?xml version="1.0" encoding="utf-8"?>
    <appwidget-provider xmlns:android="https://schemas.android.com/apk/res/android"
    
    //The layout your widget should use when it’s placed on the lockscreen on supported devices//
    
      android:initialKeyguardLayout="@layout/new_app_widget"
    
    //The layout your widget should use when it’s placed on the homescreen//
    
      android:initialLayout="@layout/new_app_widget"
    
    //The minimum space your widget consumes, which is also its initial size//
    
      android:minHeight="40dp"
      android:minWidth="40dp"
    
    //The drawable that represents your widget in the Widget Picker//
    
      android:previewImage="@drawable/example_appwidget_preview"
    
    //Whether the widget can be resized horizontally, vertically, or along both axes, on Android 3.1 and higher//  
    
      android:resizeMode="horizontal|vertical"
    
    //How frequently your widget should request new information from the app widget provider//
    
      android:updatePeriodMillis="86400000"
    
    //Whether the widget can be placed on the homescreen, lockscreen (“keyguard”) or both.//
    //On Android 5.0 and higher, home_screen is the only valid option//
    
      android:widgetCategory="home_screen"></appwidget-provider>

    如果确实为用户提供了将小部件放置在锁屏上的选项,则请记住,只要瞥一眼锁屏,任何人都可以看到该小部件的内容。 如果您的“默认”布局包含任何个人信息或潜在的敏感信息,那么您应该为窗口小部件提供另一种布局,以便将其放置在锁屏上时使用。

    res / values / dimens.xml文件

    当小部件彼此压在一起或延伸到主屏幕的最边缘时,它们看起来并不是最好的。

    每当您的窗口小部件显示在Android 4.0或更高版本上时,Android操作系统都会在窗口小部件框架和边框之间自动插入一些填充。

    小部件由边界框框架小部件边距小部件填充和小部件控件组成

    如果您的应用程序在运行Android 4.0之前版本的设备上运行,则您的小部件需要自己提供填充。

    使用“ 文件”>“新建”>“窗口小部件”>“ AppWidget”菜单创建窗口小部件时 ,Android Studio会生成两个dimens.xml文件,以确保您的窗口小部件始终具有正确的填充,无论安装了Android的版本如何。

    您将在项目的res文件夹中找到这两个文件:

    res / values / d imens.xml

    此文件定义了在API级别13或更早版本上安装时,小部件需要提供的填充的8dpi。

    <dimen name="widget_margin">8dp</dimen>

    res / values-v14 / dimens.xml

    由于Android 4.0及更高版本会自动将填充应用于每个窗口小部件,因此您的窗口小部件提供的任何填充都将是此默认填充的补充。

    为确保您的窗口小部件与用户放置在其主屏幕上的任何应用程序图标或其他窗口小部件对齐,此dimens.xml文件指定您的窗口小部件不应为Android 4.0及更高版本提供额外的边距:

    <dimen name="widget_margin">0dp</dimen>

    此默认边距有助于在视觉上平衡主屏幕,因此您应避免对其进行修改-毕竟,您不希望窗口小部件成为奇数!

    您的窗口小部件的布局已引用此尺寸值(android:padding="@dimen/widget_margin")因此在处理窗口小部件的布局时请注意不要更改此行。

    尽管这些dimens.xml文件是确保小部件始终具有正确填充的最简单方法,但是,如果该技术不适合您的特定项目,那么另一种方法是为API级别14创建多个具有不同边距的九个补丁背景以及更高的API级别13和更低的级别。 您可以使用Android Studio的Draw 9-patch工具或专用的图形编辑程序(例如Adobe Photoshop)来创建9-patch。

    项目清单

    在项目的AndroidManifest.xml文件中,您需要将小部件注册为BroadcastReceiver并指定该小部件应使用的小部件提供程序和AppWidgetProviderInfo文件。

    如果您打开清单,您会看到Android Studio已经为您添加了所有这些信息。

    //The widget’s AppWidgetProvider; in this instance that’s NewAppWidget.java//
    
    <receiver android:name=".NewAppWidget">
          <intent-filter>
    
    //An intent filter for the android.appwidget.action.APPWIDGET_UPDATE action//
    
              <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
          </intent-filter>
    
          <meta-data
              android:name="android.appwidget.provider"
    
    //The widget’s AppWidgetProviderInfo object//
    
              android:resource="@xml/new_app_widget_info" />
    
      </receiver>
    </application>

    小部件选择器资源

    res / drawable / example_appwidget_preview.png文件是可绘制资源,它表示“小部件选择器”中的小部件。

    为了鼓励用户从所有可用选项中选择您的窗口小部件,此可绘制对象应显示您的窗口小部件,并在主屏幕上对其进行正确配置并显示许多有用的内容。

    使用文件>新建>窗口小部件> AppWidget菜单创建窗口小部件时 ,Android Studio会自动生成一个可绘制的预览图( example_appwidget_preview.png )。

    在第二部分中,我将向您展示如何通过使用Android Studio的内置工具生成您自己的预览图像,来快速轻松地替换此库存可绘制对象。

    建立布局

    现在,我们对这些文件如何组合在一起以创建应用程序窗口小部件进行了概述,让我们在此基础上进行扩展并创建一个窗口小部件,其功能不仅仅是在蓝色背景上显示示例字!

    我们将在小部件中添加以下功能:

    • 显示应用程序小部件ID标签的TextView
    • 一个TextView ,它检索并显示此特定窗口小部件实例的ID。
    • 通过启动用户的默认浏览器并加载URL来响应onClick事件的TextView

    虽然我们可以简单地从Android Studio调色板中拖动三个TextViews并将它们拖放到画布上,但是如果您的小部件看起来不错,那么用户将更有可能将其放置在主屏幕上,因此让我们创建一些资源,使小部件更具视觉效果上诉。

    创建小部件的背景

    我将创建一个带有圆角,渐变背景和边框的矩形,并将其用作小部件的背景:

    • 右键单击项目的drawable文件夹,然后选择New> Drawable资源文件
    • 将此文件命名为widget_background ,然后单击“ 确定”
    • 输入以下代码:
    <?xml version="1.0" encoding="UTF-8"?>
    http://schemas.android.com/apk/res/android"
      android:shape="rectangle">
    
      <stroke
          android:width="1dp"
          android:color="#ffffff" />
    
      <gradient
          android:angle="225"
          android:endColor="#00FFFFFF"
          android:startColor="#DD000000" />
    
      <corners
          android:topRightRadius="10dp"
          android:topLeftRadius="10dp"
          android:bottomRightRadius="10dp"
          android:bottomLeftRadius="10dp" />
    </shape>

    2.创建TextView背景

    接下来,创建一个形状用作我们的TextViews的背景:

    • 右键单击项目的drawable文件夹,然后选择New> Drawable资源文件
    • 将此文件命名为tvbackground ,然后单击“ 确定”
    • 输入以下代码:
    <?xml version="1.0" encoding="utf-8"?>
    http://schemas.android.com/apk/res/android"
      android:shape="rectangle" >
    
      <stroke
          android:width="1dp"
          android:color="#000000" />
    
      <solid android:color="#FFFFFFFF" />
    
      <corners
          android:topRightRadius="15dp"
          android:topLeftRadius="15dp"
          android:bottomRightRadius="15dp"
          android:bottomLeftRadius="15dp" />
    </shape>

    3.创建一些样式

    我还将使用以下样式:

    • widget_text 我将应用于小部件文本的粗体效果。
    • widget_views 我将应用于TextViews的各种边距和填充。

    打开项目的styles.xml文件,然后添加以下内容:

    <style name="widget_views" parent="@android:style/Widget">
          <item name="android:padding">8dp</item>
          <item name="android:layout_marginTop">12dp</item>
          <item name="android:layout_marginLeft">12dp</item>
          <item name="android:layout_marginRight">12dp</item>
          <item name="android:textStyle">bold</item>
      </style>
    
    <style name="widget_text" parent="@android:style/Widget">
      <item name="android:textStyle">bold</item>
    </style>

    4.建立您的布局!

    现在我们所有的资源都到位了,我们可以创建小部件的布局了。 打开new_app_widget.xml文件并添加以下内容:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:padding="@dimen/widget_margin"
      android:background="@drawable/widget_background"
      android:orientation="vertical" >
    
      <LinearLayout
          android:background="@drawable/tvbackground"
          style="@style/widget_views"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:orientation="horizontal">
    
          <TextView
              android:id="@+id/id_label"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="@string/widget_id"
              style="@style/widget_text" />
    
          <TextView
              android:id="@+id/id_value"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="."
              style="@style/widget_text" />
      </LinearLayout>
    
      <TextView
          android:id="@+id/launch_url"
          style="@style/widget_views"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@string/URL"
          android:background="@drawable/tvbackground"/>
    </LinearLayout>

    最后,打开strings.xml文件并定义我们在布局中引用的字符串资源:

    <resources>
      <string name="app_name">Widget</string>
      <string name="widget_id">App Widget ID\u0020</string>
      <string name="URL">Tap to launch URL</string>
    </resources>

    Android Studio的“ 设计”标签可通过预览布局在各种设备上的呈现方式来帮助您更有效地工作。 与每次更改布局时,切换到“ 设计”选项卡相比在Android设备上运行项目要容易得多。

    令人沮丧的是,Android Studio不提供专用的窗口小部件外观,因此默认情况下,您的窗口小部件的布局就像常规的活动一样呈现,而无法提供对窗口小部件在用户主屏幕上的外观的最佳了解。

    一种可能的解决方法是使用Android Wear(方形)外观渲染布局,该外观可与Android应用程序小部件的大小和形状相媲美:

    • 确保选择了Android Studio的“ 设备”标签。
    • 打开设备下拉菜单。
    • 从下拉菜单中选择280 x 280,hdpi(平方)
    尝试使用Android Wear Square外观渲染小部件布局

    创建小部件功能

    现在我们的小部件看起来很重要,现在该给它一些功能了:

    • 检索并显示数据。 在将小部件的每个实例添加到App Widget Host时,都会为其分配一个ID。 即使用户将同一窗口小部件的多个实例添加到其主屏幕,该ID也会在窗口小部件的整个生命周期中保持不变,并且对于该窗口小部件实例将是唯一的。
    • 添加一个动作。 我们将创建一个OnClickListener来启动用户的默认浏览器并加载URL。

    打开窗口小部件提供程序文件( NewAppWidget.java ),然后删除检索appwidget_text字符串资源的行:

    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                              int appWidgetId) {
    
    //Delete the following line//
    
      CharSequence widgetText = context.getString(R.string.appwidget_text);
      RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
      views.setTextViewText(R.id.appwidget_text, widgetText);
    
      appWidgetManager.updateAppWidget(appWidgetId, views);
    
    }

    updateAppWidget块中,我们现在需要使用小部件的唯一ID更新R.id.id_value占位符:

    RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
          views.setTextViewText(R.id.id_value, String.valueOf(appWidgetId));

    我们还需要创建一个包含URL的Intent对象,当用户与此TextView交互时,该URL应该加载。

    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://code.tutsplus.com/"));
          PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
    
    //Attach an OnClickListener to our “launch_url” button, using setOnClickPendingIntent//
    
          views.setOnClickPendingIntent(R.id.launch_url, pendingIntent);

    这是完整的窗口小部件提供程序文件:

    import android.appwidget.AppWidgetManager;
    import android.appwidget.AppWidgetProvider;
    import android.content.Context;
    import android.widget.RemoteViews;
    import android.app.PendingIntent;
    import android.content.Intent;
    import android.net.Uri;
    
    public class NewAppWidget extends AppWidgetProvider {
    
      static void updateAppWidget(Context context,
    
                                  AppWidgetManager appWidgetManager,
    
                                  int appWidgetId) {
    
    //Instantiate the RemoteViews object//
    
          RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
    
    //Update your app’s text, using the setTextViewText method of the RemoteViews class//
    
          views.setTextViewText(R.id.id_value, String.valueOf(appWidgetId));
    
    //Register the OnClickListener//
    
          Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://code.tutsplus.com/"));
          PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
          views.setOnClickPendingIntent(R.id.launch_url, pendingIntent);
          appWidgetManager.updateAppWidget(appWidgetId, views);
    
      }
    
      @Override
      public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    
          //Update all instances of this widget//
    
          for (int appWidgetId : appWidgetIds) {
              updateAppWidget(context, appWidgetManager, appWidgetId);
          }
      }
    }

    测试小部件

    是时候对该小部件进行测试了!

    • 在您的Android设备上安装更新的项目。
    • 为确保您看到的是此窗口小部件的最新版本,请从主屏幕中删除所有现有的窗口小部件实例。
    • 按主屏幕上的任何空白部分,然后从“小部件选择器”中选择您的小部件。
    • 根据需要重新定位小部件并调整其大小。
    将您的Android应用程序小部件进行测试
    • 通过选择点击以启动URL TextView ,检查小部件是否响应用户输入事件。 应用程序小部件应通过启动默认浏览器并加载URL进行响应。

    如果您一直遵循本教程,那么此时您将拥有一个功能齐全的小部件,该小部件演示了Android应用程序小部件的许多核心概念。 您还可以从我们的GitHub存储库下载完成的项目

    结论

    在本文中,我们在构建可检索并显示一些唯一数据并对用户输入事件做出响应的小部件之前,检查了交付Android应用小部件所需的所有文件。

    当前,我们的小部件仍缺少一项主要功能:它永远不会显示任何新信息! 在下一篇文章中,我们将使此小部件能够根据设定的时间表并直接响应用户输入事件来自动检索和显示新数据。

    翻译自: https://code.tutsplus.com/tutorials/code-a-widget-for-android-input-and-display--cms-30396

    展开全文
  • 大型博客很好地利用了“关于我”页面。 为了吸引用户,有99%的时间在博客侧栏中添加了一个简短而有趣的“关于我”部分。... 我要展示的是一个聪明的小设计技巧,这个技巧被忽略了, Hongki...

    大型博客很好地利用了“关于我”页面。 为了吸引用户,他们有99%的时间在博客侧栏中添加了一个简短而有趣的“关于我”部分。 在这篇文章中,我将向您展示如何创建该部分。 就像撰写新文章一样容易。 实际上,我们将使用WordPress中的新帖子编辑器来创建它。

    帖子编辑器是WordPress中功能最丰富的工具之一,几乎没人知道。 我要向您展示的是一个聪明的小设计技巧,这个技巧被忽略了, Hongkiat.com的40个WordPress技巧列表中甚至都没有提到。

    如果您只是入门,那么这个技巧对于学习一些基本HTML和CSS也非常有用。

    建立您的讯息

    本教程所需的全部是“关于我”页面,一张自己的照片和一些文字。 您的“关于我”页面应着重于您在博客中的成就,使读者提出一些问题,并包括有关您博客的图片。 这个页面已经制作好了吗? 完善。

    现在,我们将把所有这些转移到WordPress新帖子编辑器中。 打开它,然后上传您的图像。 我们将在HTML选项卡中做很多事情 当您上传图片时,WordPress会自动为其生成HTML代码。 转到HTML标签,然后在图片上方创建一个空格(按Enter键)。 然后,在此处写一些钩子消息,例如“谁在此网站后面?” 甚至只是“关于我”。 要有创造力。

    添加新帖子

    添加新帖子

    添加简短的3-4句话描述,以吸引读者。 在此文本块的结尾,写一个句子,例如“在此处查找更多”,然后链接到实际的“关于”页面。

    设置您的留言样式

    现在转到可视选项卡。 使您的文字居中。 当您返回HTML时,您会注意到WordPress以“ p样式”的形式为您编写了一些代码。 这是在新帖子编辑器中创建小部件的美妙之处。 WordPress自动为您编写代码! 然后,您只需添加一些基本CSS!

    创建类似这样的内容:

    <p style="text-align: center; font-size: 16px; font-family: georgia, arial, verdana;"> YOUR MESSAGE </p>

    确保使用</p>关闭p样式。

    并添加您可能想到或需要的任何其他CSS。 不懂CSS吗? 只需Google搜索“ ____CSS代码”,然后在空白处输入您要执行的操作。 然后复制并粘贴p样式。 将其放在图片下方的文本块消息周围。 设置样式,然后关闭它。 如果您忘记了关闭ap样式,那没什么大不了的。 样式将应用于您想要的更多文本,但是每个人至少会犯一次此错误。

    视觉标签

    视觉标签

    使用代码<em>斜体,使用<strong>粗体显示文本,并记住也将其关闭。

    到目前为止,我们已经完成了创建,现在该开始乐趣了。

    将您的工作放在侧边栏中

    在HTML标签中,复制并粘贴您创建的所有内容。 转到外观,窗口小部件选项卡,然后将空白的文本窗口小部件拖到侧栏中。 粘贴您的代码。 然后单击“保存”,然后单击到博客的主页。 看起来如何?

    文字小工具

    文字小工具

    您几乎肯定会在这里进行一些修改。 图片可能尺寸过大,或者字体可能不像您想像的那样显示,但请放心,您可以直接在“文本”小部件中编辑所有这些内容,或者更好的是,在新的帖子编辑器中预览更改更容易。

    关于我们的最后

    关于我们的最后

    趣味造型功能和其他附加功能

    CSS确实是一个有趣的游戏。 以下是一些使“关于我”部分真正流行的方法。

    1. 使用奇异的颜色。
    2. 使用虚线或彩色边框。
    3. 在您的文本下方放置一个“选择加入”表单。 我为这些使用Aweber
    4. 添加指向您的工作地点的链接。
    5. 开个玩笑,或者变得神秘。

    影片教学

    您也可以在下面或在YouTube上观看此帖子的视频教程。

    下一步是什么?

    现在您已经有了基本的关于我部分和关于我页面,请浏览其他博客以了解适用于它们的策略和设计。 做一些笔记。 然后,对您自己的读者进行更多研究。

    完全根据读者的需求量身定制“关于我”,最终您将开始看到更多的读者,评论员和忠实的订阅者。 把自己放在侧边栏中,最后值得这样做。

    编者注:本文由Greg Narayan为Hongkiat.com撰写。 格雷格(Greg)是来自纽约的25岁男孩,他在早餐前回答了大约150个博客问题。


    翻译自: https://www.hongkiat.com/blog/wordpress-about-me/

    展开全文
  • 6个出色基于JQueryTab选项卡实例

    千次阅读 2010-12-02 03:01:00
    1. jQuery 选项卡界面 / 选项卡结构菜单教程 这种类型菜单在网页设计与开发中非常著名。此片教程是向大家展示如何使用jQuery向下...一个在列表之上简易(via CSS)导航条,向用户展示从A到Z检索

    1. jQuery 选项卡界面 / 选项卡结构菜单教程
    这种类型的菜单在网页设计与开发中非常著名的。此片教程是向大家展示如何使用jQuery的向下滑动/向上滑动效果创建属于你自己的选项卡菜单。要非常留心此演示哟,你一定会喜欢上它的。
    演示 | 下载 | 介绍

    2. jQuery目录导航插件
    这个jQuery插件为我们提供了添加基于字母顺序的导航小部件到有序和无序列表的方法。一个在列表之上的简易的(via CSS)导航条,向用户展示从A到Z的检索。通过从列表中选择一个字母来显示以此字母开头的所有元素。在可选字母上面显示的计数,是表明当你点击此字母的时候会有多少项目被现实。除此之外还有其他的基本功能可供选择。
    演示 | 下载 | 介绍

    3. jQuery的Kwicks菜单
    Kwicks起源于Mootools中的一个效果(相同名字),逐渐演变成一个高度可定制的通用部件.
    演示 | 下载 | 介绍

    4. jQuery褪色菜单 -更换内容
    CSS-tricks上很好的教程,讲解如何使用css和jQuery, 这次是他们教导如何使用 jquery使得菜单选项褪色。
    演示 | 下载 | 介绍

    5. jQuery idTabs
    idTabs是jQuery的插件。他能非常容易的为网站添加选项卡. 但是他也为无穷的可能性敞开大门。
    演示 | 下载 | 介绍

    6. jQuery + CSS创建顺畅的选显卡内容区
    网页设计师设法把大量的信息浓缩在一个网页上而不失可用性是最大的挑战之一。内容选项卡化是处理此类问题非常棒的方法,最近广泛被应用于博客。这是一篇非常棒的教程讲解,使用HTML建立一个小的选项卡信息盒,最后使用一些简单js功能与jQuery库实现。
    演示 | 下载 | 介绍

    展开全文
  • 我学习Django(总览)

    2018-04-17 18:11:25
    v代表view,用于向用户展示结果;c代表controller是核心,用于处理请求,获取数据,返回结果;)MVC框架 核心思想:结藕 降低各功能之间耦合性,方便变更,更容易重构代码,最大程度上实现代码重用。高可扩展...
  • 两个SDK示例( 和 )展示了如何使用简单CheckedTextView小部件来代表行来完成此操作。 但是,当您要使用自定义布局来表示行时,需要花一些时间来弄清为什么未选中项目原因。嗯,到本教程结束时,您应该知道...
  • 第二个示例Web应用程序 我将使用另一个小部件解决本文最后3个问题,并且在深入研究其代码之前展示和解释它。这个401k小部件并不陌生,因为您已经在前面文章见过它...如果它们和不为100,我将向用户
  • 使用MooTools,jQuery或Dojo创建一个Twitter AJAX按钮 没有什么比有效地使用CSS和JavaScript增强用户体验微妙,光滑网站窗口小部件更好了。 当然,像这样窗口小... 让我展示如何使用三种流行JavaSc...
  • 操作系统1- 概述

    2015-10-26 16:40:25
    1.通过抽象隐藏机器复杂性,向用户展示机器(电脑)信息。   2.资源管理者,控制所有机器各个部件。充分协调各个部件工作,发挥最大效能。   3.资源共享,通过资源共享,充分地使用处理器,内存,硬盘...
  • 学习HTML5表单笔记

    2020-07-08 22:26:54
    datalist元素:用于为文本框提供一个可选择...通常,这是作为一个下拉框向用户展示,在输入框中输入可能匹配内容。(option也可以写成下面这样) 2.HTML5表单新增属性 ①autocomplete属性: 规定表单是否应该启
  • ThinkPHP之MVC简析

    2017-01-20 17:01:00
    MVC是一种设计模式。它强制性使用程序输入、处理和输出...视图——通过模板(布局)向用户展示数据控制器——接受用户请求,并调用相应模型处理;选择不同视图展示数据。 MVC设计模式优点: (1)利用Con...
  • 如今,几乎每个平凡移动应用都可能在其布局中包含列表。 那是因为使用可滚动列表通常是在小... 如果您需要显示少量相似项目,并且可以确保用户的屏幕能够同时容纳所有这些项目,那么使用Column小部件是最有效...
  • HTML5桌面通知示例

    2012-11-20 00:00:00
    所以,今天我做了一个快速演示展示使用HTML5和JavaScript小桌面通知例子。 查看项目在GitHub上 HTML5桌面提醒背景资料 通知允许警报发生,网页上下文之外的用户,例如电子邮件递送。 您可以...
  • excel使用

    2012-11-25 17:06:01
    自定义函数,也叫用户定义函数,是Excel最富有创意和吸引力功能之一,下面我们在Visual Basic模块中创建一个函数。 在下面例子中,我们要给每个人金额乘一个系数,如果是上班时工作餐,就打六折;如果是加班...
  • thinkphp学习笔记(1)

    2016-07-14 16:44:00
    MVC是一种设计模式,它强制性地使应用程序输入,处理个输出分离。...视图:通过布局向用户展示数据。 控制器:接受用户请求,并调用相应模型处理。 转载于:https://www.cnblogs.com/wuxy1...
  • 当 Eclipse 更新站点中有某个新插件或已更新插件可用时,应该让您 IBM Lotus Sametime 用户获知该情况。本文将展示创建包含可添加到 Sametime 操作栏功能部件的更新站点有多么轻松。 软件应用...
  • 音高排序-源码

    2021-02-16 11:17:10
    音高排序 这里想法是,我们可以跟踪不同音高音高不同序列,因此我们可以确定它们应如何将音高配对... 下一步需要开发一个平台或小部件,无论用户是否熟悉Python作为平台,它都可以使用户轻松访问和使用这些功能。
  • 电源线或电源内部产生的干扰,它是通过电源线或电源内的部件耦 合或直接传导,可通过电源滤波、隔离等措施来衰减该类干扰。 内因:振荡源的稳定性,主要由起振时间频率稳定度和占空比稳定度决定 起振时间可由电路...
  • 在本教程中,我们展示如何执行以下任务: 渲染XML微调框,并通过XML文件加载选择项。 使用XML渲染另一个Spinner,并通过代码动态加载选择项。 在Spinner上附加一个侦听器,当用户在Sp...
  • WidgetKit初探

    2020-10-26 16:25:03
    为了使窗口小部件支持用户可配置,可以扩展中添加自定义SiriKit意向定义,WidgetKit自动提供自定义界面,让用户自定义widget。 一、创建Widget Extension 1、添加widget target (1)添加步骤 File–>new–>...

空空如也

空空如也

1 2 3
收藏数 58
精华内容 23
关键字:

向用户展示的部件