Ⅰ android StackView 怎么设置只显示3个item
是否点击的标志仅需要存储1个positio就够了
因为这是同时也只会有一个隐藏并且隐藏之后也无法点击了只能点击未隐藏的所以要实现这个功能只需要
2个注意的点:
1 定义一个全局变量用来存储需要隐藏的item的position
2 给listview设置一个点击监听setonitemclickListener
getview里面做一个判断如果当前position等于存储得position隐藏掉这个view
当点击了listview 更新一下全局变量并且调用notifydatachanged刷新一下adapter
Ⅱ android 自定义通知栏
Notification 参数使用 参考:
http://www.cnblogs.com/kexing/p/8371051.html
自定义通知栏
仅支持FrameLayout、LinearLayout、RelativeLayout三种布局控件
AnalogClock、Chronometer、Button、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView和AdapterViewFlipper这些显示控件
否则会引起ClassNotFoundException异常。
流程:点击通知栏 发送广播 app接收广播做相应处理:
为通知栏绑定广播事件:
1.FLAG_CANCEL_CURRENT:如果AlarmManager管理的PendingIntent已经存在,那么将会取消当前的PendingIntent,从而创建一个新的PendingIntent.
2.FLAG_UPDATE_CURRENT:如果AlarmManager管理的PendingIntent已经存在,让新的Intent更新之前Intent对象数据,例如更新Intent中的Extras,另外,我们也可以在PendingIntent的原进程中调用PendingIntent的cancel ()把其从系统中移除掉
3.FLAG_NO_CREATE:如果AlarmManager管理的PendingIntent已经存在,那么将不进行任何操作,直接返回已经.
4.FLAG_ONE_SHOT:该PendingIntent只作用一次.在该PendingIntent对象通过send()方法触发过后,PendingIntent将自动调用cancel()进行销毁,那么如果你再调用send()方法的话,系统将会返回一个SendIntentException.
添加广播接收:
AndroidManifest:
Ⅲ 为什么栅格系统以8为基数好处有哪些
之前写过一个关于 栅格系统 的简述文章;现在来看只能作为简单的视觉布局参考,更多的是从排版布局的角度出发。最近被问到选择几作为栅格基数比较好这个问题,对此做一下整理。
其实栅格在各个平台开发布局中都有所定义。
通俗介绍 简单了解一下开发布局中栅格的变革
Web端最常见的布局 Bootstrap ;
它是Twitter的设计师Mark Otto和Jacob Thornton合作开发的一款强大的前端框架,至今仍被广泛使用,已经更新到V4版本了。
Bootstrap 中的栅格系统是一套响应式、移动设备优先的瀑布流式栅格系统。
它将系统分为12列,当然也可以通过变量来改变列数和列宽,水槽宽度,屏幕浮动宽度;
其实设置屏幕浮动宽度就是我们看到的屏幕自适应,就是根据屏幕宽度来选择显示参数。
Bootstrap 中的栅格流只能作为大的布局定义,那么针对最小单位是该用8、10、15还是多少也是需要根据需求去做分析。
iOS布局方式很多,常用的可以归纳为 Frame、Autoresizing、Constraint、StackView 和 Masonry 五种;
其中,
Frame 用来描述UIView的位置和大小;
Autoresizing 早期用来适配屏幕;
Constraint 比 Autoresizing 更加灵活,适配效果更好;
了解一下,
StackView 它是iOS9时新增的一个视图类,可以把它理解成一个容器,添加到容器内的控件可以按照行或列进行布局。
Masonry 是一个轻量级的布局框架,是基于 NSLayoutConstraint 的一种第三方框架;通俗来讲用它实现适配布局更简洁更轻量。
先简单了解一下Android开发中的六大基本布局
LinearLayout 线性布局:最常用的以垂直和水平方向的布局方式
RelativeLayout 相对布局:可以基于父或兄弟控件来布局
FrameLayout 层布局:就是控件盖控件的那种布局方式
AbsoluteLayout 绝对布局:基于绝对坐标xy布局,无法自适应
了解一下,
TableLayout 表格布局:多行多列的布局方式
GridLayout 网格布局:以网格的方式进行布局
在引入的表格布局和网格布局中其实就是为了更加方便系统栅格化
根据以上内容对于三大平台的常用布局做一个简单的分析
总结:
Web端引入的Bootstrap、Android端的表格和网格布局以及iOS9之后引入的Stachview和Masonry都是为了能更好的适配以及进行系统的栅格布局;
也体现了设计中需要栅格定义的重要性。
以上布局框架仅是从开发层面的一个布局演变
看到过很多关于栅格布局的文章,现在理解觉得有些片面,可能仅是作为从设计的角度去理解, 很多的栅格方式都是从平面排版设计中的栅格演变过来的,基数可能比较随性,并且没有严格贴合系统去做。
站在巨人的肩膀上,还是从这三大平台来看,看一下官方给出的建议。
简单看一下Bootstrap的栅格参数, 通过下表可以详细查看 Bootstrap 的栅格系统是如何在多种屏幕设备上工作的。
由表知Bootstrap的默认水槽宽度是30px(每列左右是15px),当然这些是可自定义的,Bootstrap的主要目的是为了适配屏幕进行自适应布局;
我们设计时设置栅格的时候大多数情况下是以非自适应网页来做的栅格,栅格最小单位一般是10,15等不定参数;
虽然Web端的可视范围比较大浏览方式和移动端不一样,
但是我们发现针对一些内容较多的网页或者说对卡片内的信息去做布局,基数是10或15就会很难呈现出想要的效果。
以8为基数的栅格系统渐渐被使用,以8为基数 好在哪里?
之前国外的一个博客中( spec.fm *一个开发者和设计师共同搭建的博客,设计细节中会从多个纬度去考量), 有 一篇文章 提到过使用8点栅格的好处。
总结一下他们在Web端分析出的好处点有哪些;
Bootstrap或其他的框架只作为一个大的布局系统,对于设计 没有一个设计单位去衡量 排版很难一致性,使用8点的好处在哪:
对于设计: 效率, 减少决策 ,同时能 保持元素之间的节奏 。
对于团队: 开发人员 更容易理解 ,在开发眼里8更有说服性。
对于用户: 一致审美 ,减少设备上出现模糊的 半像素偏移 问题。
我们来看iOS的 Human Interface Guidelines 如何去给出布局建议。
iOS是个封闭的系统,在 Human Interface Guidelines 可以看到iOS使用Auto Layout自动布局,iOS的系统完全自主更新,终端设备也完全由自己决定,因此系统可以做到强制规范化。但在这里提到的基数也是 8 。
在布局中说到的约束,就是我们来定义的栅格基数,他给的建议也是 8 。
下边我们找一下iOS官方组件,看一下自适应布局的限制区域是不是基数 8 。
在Sketch中置入一个iOS官方页面组件将其拆解:
其实我们发现在iOS系统设计中的基数也是以8为基准。
上边说到的 Spec.fm 中的那篇文章中有提到Points,关于iOS的@1x,@2x,@3x图,用 8 为基数可减少出现是奇数造成一像素偏移模糊的情况。
Android端的 Material Design 布局给出的建议。
在 Material Design 给出的建议中是以8dp为基准,小的控件以4dp为基准。
Material Design 定义的栅格布局更像Bootstrap,它可以适应多平台,结合它丰富的视觉语言能搭建出更加严谨的移动应用或网页。
站在巨人的肩膀上
从以上三大平台来看,移动端官方给出的建议都是以8为基准。
从以上分析 我个人觉得,
从系统的角度,首先要保证是偶数;只研究移动端平台: 2、4、6、8、10 ;
其实 我觉得用2的次方计算会更加贴合: 2^1、2^2、2^3、2^4 : 2、4、8、16 ;
在这些数字中2作为基数太小了我们视觉能看到的2个点太小,并且使用起来很麻烦每次都要进行计算;
那么10或16作为基数又太大了,在移动端很难避免信息过多小屏幕需要考虑排版的问题;
取在这两组数中的交集还剩下 4 和 8 ;
以上Material Design给出的建议中也是以8为基准,小的控件以4为基准。
从很多角度来看 8 点栅格是最为理想的栅格基础单位
下面再总结一下8点栅格的好处:
1、Web端布局更加灵活。
2、视觉一致性,保证元素之间的节奏。
3、减少出现奇像素偏移造成模糊。
4、开发更容易理解的数字8。
5、能被最多的屏幕尺寸整除适配,这也是Material Design和iOS建议的主要原因之一。
END / THX
Ⅳ 如何在Android实现桌面清理内存简单Widget小控件
一、UI部分的编写:
参照Google的文档,首先在建立一个类继承 AppWidgetProvider
import android.appwidget.AppWidgetProvider;
public class MyWidget extends AppWidgetProvider {
}
然后在清单文件中申明它,我们必须注意到,AppWidgetProvider实际上是BroadcastReceiver,所以要注册成一个receiver,然后还有一些其他的东西需要注意:
<receiver android:name="com.alexchen.widget.MyWidget" >
<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.appwidget.action.APPWIDGET_UPDATE
表明这个receiver能够接受一个APPWIDGET_UPDATE的广播,而且在这里,只能加入这一个action。
android.appwidget.provider 表明数据类型时widget提供者提供的数据,example_appwidget_info 表明这个widget的参数配置文件名和位置
那么接下来就需要在res目录下建立一个xml文件夹,并且在其中建立一个example_appwidget_info.xml 的配置文件,Google的文档中给出了示例有很多参数,实际上关键的参数只有下面的4个:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="94dp"
android:minHeight="72dp"
android:updatePeriodMillis="86400000"
android:initialLayout="@layout/example_appwidget">
</appwidget-provider>
其中, minWidth 和 minHeight 代表这个widget控件所占据的最小空间,这个空间一般来讲不需要太大,因为太大的话,一个屏幕可能都没办法放下,Google的官方文档的说法是大于4x4的就可能无法显示。
updatePeriodMillis 代表数据更新的时间,这里86400000毫秒实际上是24小时,可能最开始看到这个参数会想我能否将其设的很小,每一秒刷新很多次?, 实际上对于updatePeriodMillis 这个参数而言, 即算你设的再小也没用,Google设定widget控件这个参数控制的最短update时间为30分钟,就算将其设置在30分钟以内也会以30分钟的频率来更新数据。
initialLayout 参数代表的是本widget空间的布局文件。
那么下一步就是定义出一个对应的布局文件。我们可以简单的在layout目录下建立一个布局文件example_appwidget.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="200dp"
android:layout_height="80dp"
android:background="@android:color/white"
android:gravity="center_vertical"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_widget"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="widget控件测试"
android:textColor="@android:color/black"
android:textSize="15sp" />
<Button
android:id="@+id/btn_clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="清理内存"
android:textColor="#ff000000" />
</LinearLayout>
在Google的文档中有指出,并非所有的布局组件都可以在上面的这个布局中生效,有效的组件或布局为:
FrameLayout
LinearLayout
RelativeLayout
GridLayout
AnalogClock
Button
Chronometer
ImageButton
ImageView
ProgressBar
TextView
ViewFlipper
ListView
GridView
StackView
AdapterViewFlipper
至此,一个简单的widget控件就写好了,我们可以在模拟器上将其拖到桌面上看一看效果:
二、功能逻辑部分的实现
大部分的Widget小控件都会需要在特定情况下更新上面显示的数据,那么这个是如何实现的呢,我们经过上面的代码不难发现实际上这个widget控件并没有一个Activity,所以说这个控件的显示实际上不是本应用来实现的,它实际上是桌面这个应用来显示的,所以我们也不可能直接去更新它上面的数据。
回过头去看看上面我们写的那个receiver,实际上没有实现任何方法。实际上AppWidgetProvider里面有几个比较重要的方法: onReceive、 onUpdate、onDisabled、onEnabled
其中 onReceive 方法跟大多数广播接收者的onReceive方法一样,但是在这里,onReceive方法的调用并不是我们可以决定的, 它依赖于显示该widget控件的Host组件,在这里也就是Android桌面应用,所以我们会发现在不同的手机上,将widget控件拖到桌面上显示的时候onReceive可能调用的次数和先后顺序可能完全不一样,这依赖于Host组件是如何实现的。
所以在这里onReceive方法对于我们刷新widget数据基本没有什么帮助。
而 onUpdate 方法则是由上面所说的 updatePeriodMillis 参数来控制的,经过上面的分析,我们都知道了,它的最小周期为30分钟。所以我们一般将这个参数设为0即可。那么在这个方法里,我们往往会在其中放置一些启动更新数据服务的功能,因为如果后台的更新数据的Service被意外停止了,那么每30分钟还会被重新启用,不至于一直启动不了了:
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
// System.out.println("onUpdate");
//每隔一段时间重新启动服务,防止服务中间被终止了之后没法重启
Intent intent = new Intent(context, UpdateWidgetService.class);
context.startService(intent);
}
下面是比较重要的两个方法了:
onDisabled和onEnabled
我们知道,widget 小控件是可 以拖动多个到桌面上的,而 onEnabled 方法会在第一个widget控件拖到桌面上的时候调用一次, onDisabled 会在最后一个widget控件从桌面被删除时调用一次,那么我们需要做的就是在 onEnabled 这个方法中启用一个刷新widget数据的服务,在 onDisabled 方法中使用 stopService 方法来停止这个服务。
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
System.out.println("onDisabled");
//停止数据刷新服务
Intent intent = new Intent(context, UpdateWidgetService.class);
context.stopService(intent);
}
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
System.out.println("onEnabled");
//开启数据刷新服务
Intent intent = new Intent(context, UpdateWidgetService.class);
context.startService(intent);
}
三、刷新数据的服务
那么下面的任务就只剩下 UpdateWidgetService 这个刷新数据的服务(Service)如何实现的问题了。
我们在这里的想法很简单,比如说每隔三秒钟来刷新一下widget中的数据。Android中定时执行任务的方法有很多,我们这里使用 Timer 和 TimerTask 来实现,之后我们需要关心的就是具体如何实现刷新widget中的数据,毕竟这些数据是在桌面应用中显示的。
并且我们需要用到一个API-- AppWidgetManager ,它有一个实例方法AppWidgetManager .updateAppWidget( ComponentName provider, RemoteViews views) 来实现更新widget数据,我们都知道,如果需要调用另外应用的方法,需要使用远程调用的方法来实现,在这里起到在我们的应用和桌面应用之间的桥梁作用的就是这第二个参数:RemoteViews views, 它会将我们设置的数据传送到桌面应用来刷新widget上的数据,我们需要经过下面几步:
1、定义一个RemoteViews的实例:
RemoteViews views = new RemoteViews(getPackageName(),R.layout.process_widget);
2、设置views的内容,也就是刷新其中的数据,这里的方法名会比较奇怪,RemoteViews .setTextViewText( int viewId, CharSequence text)
其中viewId是在我们前面定义的widget布局文件中的子组件的id,也就是我们要刷新内容的对象,这里就是R.id.tv_test,第二个参数是我们要更新的内容
3、定义好第一个参数ComponentName provider 之后,就可以调用AppWidgetManager .updateAppWidget( ComponentName provider, RemoteViews views) 来实现更新数据
if (timer == null && task == null) {
//AppWidgetManager对象,用于更新widget的数据
awm = AppWidgetManager.getInstance(this);
timer = new Timer();
task = new TimerTask() {
@Override
public void run() {
ComponentName provider = new ComponentName(UpdateWidgetService.this, MyWidget.class);
//远程view对象,用于在本应用和桌面应用中起传递数据的桥梁作用
RemoteViews views = new RemoteViews(getPackageName(),R.layout.example_appwidget);
views.setTextViewText(R.id.tv_widget, "想刷新的数据的内容");
awm.updateAppWidget(provider, views);
System.out.println("====刷新了widget====");
}
//设置循环时间
timer.schele(task, 0, 3000);
}
四、定时刷新可用内存和一键清理内存功能实现
要实现这个功能,我们需要再上面定时刷新数据服务中将定时刷新的内容改为当前内存所剩余的量,我们这里写一个工具类方法来实现返回内存剩余量;
另外我们还需要在widget控件的布局文件中添加一个button,并在更新widget数据的服务中,设置这个button的点击事件,但是这里也不像以前的点击事件,同样要应用到RemoteView对象,在这个点击事件中需要发送一个广播,Action为自定义的,我们这里设为: "com.alexchen.mobilesafeexercise.killall" ,之后,我们需要再写一个广播接收者,来接收这个广播,在onReceive方法中执行杀死后台进程的操作。这里也不能直接使用Intent,由于我们这个意图的Action不是由我们自己执行而是由其他应用程序(桌面应用)执行的,所以需要用到 PendingIntent 。
刷新widget数据的服务代码:
package com.alexchen.widget.service;
import java.util.Timer;
import java.util.TimerTask;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.text.format.Formatter;
import android.widget.RemoteViews;
import com.alexchen.widget.MyWidget;
import com.alexchen.widget.R;
import com.alexchen.widget.utils.SystemInfoUtils;
public class UpdateWidgetService extends Service {
private Timer timer;
private TimerTask task;
private AppWidgetManager awm;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
startTimer();
}
private void startTimer() {
if (timer == null && task == null) {
awm = AppWidgetManager.getInstance(this);
timer = new Timer();
task = new TimerTask() {
@Override
public void run() {
ComponentName provider = new ComponentName(
UpdateWidgetService.this, MyWidget.class);
RemoteViews views = new RemoteViews(getPackageName(),
R.layout.example_appwidget);
views.setTextViewText(R.id.tv_widget, "dd");
views.setTextViewText(R.id.tv_widget,
"可用内存:"+ Formatter.formatFileSize(getApplicationContext(),
SystemInfoUtils.getAvailableMem(getApplicationContext())));
// 自定义一个广播,杀死后台进程的事件
Intent intent = new Intent();
intent.setAction("com.alexchen.mobilesafeexercise.killall");
// 描述一个动作,这个动作是由另外一个应用程序执行的
PendingIntent pendingIntent = PendingIntent.getBroadcast(
getApplicationContext(), 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.btn_clear, pendingIntent);
awm.updateAppWidget(provider, views);
System.out.println("====刷新了widget====");
}
};
timer.schele(task, 0, 3000);
}
}
@Override
public void onDestroy() {
super.onDestroy();
stopTimer();
unregisterReceiver(offReceiver);
unregisterReceiver(onReceiver);
}
private void stopTimer() {
if (timer != null && task != null) {
timer.cancel();
task.cancel();
task = null;
timer = null;
}
}
}
按键清理内存的广播接收者:
package com.alexchen.widget.receiver;
import java.util.List;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class KillAllReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("自定义的广播消息接收到了...开始清理内存...");
ActivityManager am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> runningAppProcesses = am
.getRunningAppProcesses();
for (RunningAppProcessInfo info : runningAppProcesses) {
am.killBackgroundProcesses(info.processName);
}
}
}
获取可用内存的工具类方法:
/**
* 获取手机可用的剩余内存
*
* @param context
* 上下文
* @return
*/
public static long getAvailableMem(Context context) {
ActivityManager am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
MemoryInfo outInfo = new MemoryInfo();
am.getMemoryInfo(outInfo);
return outInfo.availMem;
}
Ⅳ android stackview是否有缓存
当然有啦
Ⅵ android通知栏怎么添加控件
Notification的自定义布局是RemoteViews,和其他RemoteViews一样,在自定义视图布局文件中,仅支持FrameLayout、LinearLayout、RelativeLayout三种布局控件和AnalogClock、Chronometer、Button、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView和AdapterViewFlipper这些显示控件,不支持这些类的子类或Android提供的其他控件。否则会引起ClassNotFoundException异常
步骤如下:
1)创建自定义视图
2)获取远程视图对象(注:Notification的contentView不能为空)
3)设置PendingIntent(来响应各种事件)
4)发起Notification
大体4步骤这里就不详细说了,下面就把DEMO中的列子拿出来说下
样式:
1.自定义带按钮通知栏(如下样式)
正在进行的
“正在进行的”通知使用户了解正在运行的后台进程。例如,音乐播放器可以显示正在播放的音乐。也可以用来显示需要长时间处理的操作,例如下载或编码视频。“正在进行的”通知不能被手动删除。
实现方法如下:
实现方法如下:
/**
*带按钮的通知栏
*/
publicvoidshowButtonNotify(){
NotificationCompat.BuildermBuilder=newBuilder(this);
RemoteViewsmRemoteViews=newRemoteViews(getPackageName(),R.layout.view_custom_button);
mRemoteViews.setImageViewResource(R.id.custom_song_icon,R.drawable.sing_icon);
//API3.0以上的时候显示按钮,否则消失
mRemoteViews.setTextViewText(R.id.tv_custom_song_singer,"周杰伦");
mRemoteViews.setTextViewText(R.id.tv_custom_song_name,"七里香");
//如果版本号低于(3。0),那么不显示按钮
if(BaseTools.getSystemVersion()<=9){
mRemoteViews.setViewVisibility(R.id.ll_custom_button,View.GONE);
}else{
mRemoteViews.setViewVisibility(R.id.ll_custom_button,View.VISIBLE);
}
//
if(isPlay){
mRemoteViews.setImageViewResource(R.id.btn_custom_play,R.drawable.btn_pause);
}else{
mRemoteViews.setImageViewResource(R.id.btn_custom_play,R.drawable.btn_play);
}
//点击的事件处理
IntentbuttonIntent=newIntent(ACTION_BUTTON);
/*上一首按钮*/
buttonIntent.putExtra(INTENT_BUTTONID_TAG,BUTTON_PREV_ID);
//这里加了广播,所及INTENT的必须用getBroadcast方法
PendingIntentintent_prev=PendingIntent.getBroadcast(this,1,buttonIntent,PendingIntent.FLAG_UPDATE_CURRENT);
mRemoteViews.setOnClickPendingIntent(R.id.btn_custom_prev,intent_prev);
/*播放/暂停按钮*/
buttonIntent.putExtra(INTENT_BUTTONID_TAG,BUTTON_PALY_ID);
PendingIntentintent_paly=PendingIntent.getBroadcast(this,2,buttonIntent,PendingIntent.FLAG_UPDATE_CURRENT);
mRemoteViews.setOnClickPendingIntent(R.id.btn_custom_play,intent_paly);
/*下一首按钮*/
buttonIntent.putExtra(INTENT_BUTTONID_TAG,BUTTON_NEXT_ID);
PendingIntentintent_next=PendingIntent.getBroadcast(this,3,buttonIntent,PendingIntent.FLAG_UPDATE_CURRENT);
mRemoteViews.setOnClickPendingIntent(R.id.btn_custom_next,intent_next);
mBuilder.setContent(mRemoteViews)
.setContentIntent(getDefalutIntent(Notification.FLAG_ONGOING_EVENT))
.setWhen(System.currentTimeMillis())//通知产生的时间,会在通知信息里显示
.setTicker("正在播放")
.setPriority(Notification.PRIORITY_DEFAULT)//设置该通知优先级
.setOngoing(true)
.setSmallIcon(R.drawable.sing_icon);
Notificationnotify=mBuilder.build();
notify.flags=Notification.FLAG_ONGOING_EVENT;
mNotificationManager.notify(notifyId,notify);
}
如果您对回答满意,请关注一下俺的微博
Ⅶ iOS 开发中能不能使用类似CSS的方式做到样式和内容分离
基于MVC的快速开发框架 Bee Framework 是一款iOS快速开发框架,允许开发者使用Objective-C和XML/CSS来进行iPhone和iPad开发,由 Gavin Kwoe 和 QFish 开发并维护。
这套布局库是以android的线性布局,相对布局,框架布局,表格布局为蓝本。同时又具有IOS的AutoLayout的功能,和部分SIZECLASS功能,以及IOS9中的UIStackView的功能,参考了masonry的一些语法机制,但是他却可以运行在IOS5版本的应用中。使用简单方便,代码清晰,而且少。 并且附带四篇教程文档:
Ⅷ 谁知怎么自定义StackView控件
这就是你遇到的问题的,呵呵
Ⅸ 谁知怎么自定义StackView控件
1,配置文件.xml文件中的属性,目前只知道两个
<com.youku.widget.YoukuHomePageStackView
android:id="@+id/homepage_stackview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:loopViews="true"
android:layerType="hardware"
/>
android:loopViews:控制是否是轮播效果,能被翻动的,设置为true,就可以被翻动;设置为false,就不能被翻动。。
android:layerType:是设置是否是硬件加速的问题,是为解决布局StackView是在ActionBar下面,自动轮播时候,每一个StackView的Item会翻上来遮挡ActionBar。
还有none,这个是默认属性,这个属性就是不进行硬件加速;还有software,这是硬件加速中的软件加速属性,据说如果手机不支持hardware,那么这个
属性自动会变成software属性。。。。
2,重写StackView控件
package com.youku.widget;
import java.util.Timer;
import java.util.TimerTask;
import com.youku.util.Logger;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.StackView;
import android.support.v4.view.ViewPager;
@SuppressLint("NewApi")
public class YoukuHomePageStackView extends StackView {
public static final String TAG = "LXF";
float dispatchDownXDistance = 0;
float dispatchUpXDistance = 0;
float dispatchDownYDistance = 0;
float dispatchUpYDistance = 0;
private boolean isAutoSlideMode;
private Timer timer;
private TimerTask task;
private static final int MSG_SLIDE = 10000110;
private static final int PERIOD = 5000;
private ViewPager viewPagerFragment;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MSG_SLIDE:
showNext();
sendEmptyMessageDelayed(MSG_SLIDE, PERIOD);
break;
default:
break;
}
}
};
public YoukuHomePageStackView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
Logger.lxf("====onWindowVisibility===visibility===="+visibility);
if(visibility == View.VISIBLE) {
startAutoSlide();
} else {
cancleTask();
}
}
//自动轮播方法,使用handler来实现自动轮播
public void startAutoSlide() {
cancleTask();
handler.sendEmptyMessageDelayed(MSG_SLIDE, PERIOD);
// isAutoSlideMode = true;
// if (timer == null) {
// timer = new Timer();
// task = null;
// task = new TimerTask() {
//
// @Override
// public void run() {
// // F.ot("prove i'm live");
// Message m = Message.obtain();
// m.what = MSG_SLIDE;
// handler.sendMessage(m);
// }
// };
// }
// timer.schele(task, PERIOD, PERIOD);
}
public void cancleTask(){
handler.removeMessages(MSG_SLIDE);
// if(null!=timer){
// timer.cancel();
// timer.purge();
// timer = null;
// }
//
// if(null!=task){
// task.cancel();
// task = null;
// }
}
public void removeAllView(){
removeAllViews();
}
//监听这个方法主要是为了在ViewPager和StackView之间的事件点击之间冲突问题。。。
//当StackView被点击的时候,会触发dispatchTouchEvent()中的Action_DOWN动作,此时()设置为true,则此时ViewPager不会被触发,只有StackView才能被触发。。。
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch(action){
case MotionEvent.ACTION_DOWN:
viewPagerFragment = (ViewPager)getParent().getParent().getParent().getParent().getParent().getParent().getParent();
dispatchDownXDistance = ev.getX();
dispatchDownYDistance = ev.getY();
cancleTask();
getParent().(true);
// return true;
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
dispatchUpXDistance = ev.getX();
dispatchUpYDistance = ev.getY();
float distanceMoveOne = dispatchUpXDistance-dispatchDownXDistance;
float distanceMoveTwo = dispatchDownXDistance-dispatchUpXDistance;
float distanceMoveY = dispatchUpYDistance-dispatchDownYDistance;
// Logger.lxf("distanceMoveY=="+distanceMoveY);
// Logger.lxf("Math distanceMoveY=="+Math.abs(distanceMoveY));
// Logger.lxf("Math distanceMoveOne=="+Math.abs(distanceMoveOne));
getParent().(false);
startAutoSlide();
if(distanceMoveOne>100&&Math.abs(distanceMoveY)<30){
//向左滑动
viewPagerFragment.setCurrentItem(1);
return false;
}else if(distanceMoveTwo>100&&Math.abs(distanceMoveY)<30){
//向右滑动
viewPagerFragment.setCurrentItem(3);
return false;
}
break;
case MotionEvent.ACTION_CANCEL:
startAutoSlide();
break;
}
return super.dispatchTouchEvent(ev);
}
}