当前位置:  编程技术>移动开发
本页文章导读:
    ▪NSRunLoop的一点理解      一、类定义  + (NSRunLoop *)currentRunLoop    如果调用的线程中没有runloop,那么将会创建一个并返回  + (NSRunLoop *)mainRunLoop    返回主线程的runloop  - (void)acceptInputForMode:(NSString *)mod.........
    ▪WP8中 ListBox x下拉刷新 以及 ScrollViewer/ListBox 的ManipulationCompleted 失效的解决方案      本文同步发表于 Windows Phone论坛 WPDEVN :http://www.wpdevn.com/showtopic-138.aspx今天在做 Wp8  中的ListBox 下拉刷新 发现一个蛋疼的问题 ManipulationCompleted   失效 这个事件死活不会触发 。。。 .........
    ▪android 自定义RadioButton(单选按钮)图标随便定.      RadioButton在我们开发APP应用中是很常见的.这点我不用说大家也心知肚明.         虽说Android 系统给我们提供了RadioButton但是为了我们的应用有种"与众不同"的效.........

[1]NSRunLoop的一点理解
    来源:    发布时间: 2013-11-15

一、类定义

  + (NSRunLoop *)currentRunLoop
    如果调用的线程中没有runloop,那么将会创建一个并返回
  + (NSRunLoop *)mainRunLoop
    返回主线程的runloop

  - (void)acceptInputForMode:(NSString *)mode beforeDate:(NSDate *)limitDate
    运行loop一次或者直到limitDate。如果没有input sources加入到这个loop,那么马上返回;否则一直运行到limitDate,或者接口到一个input source然后返回。
  - (void)addPort:(NSPort *)aPort forMode:(NSString *)mode
  - (void)addTimer:(NSTimer *)aTimer forMode:(NSString *)mode
    port和timer都可以添加到多个mode中
  - (void)cancelPerformSelector:(SEL)aSelector target:(id)target argument:(id)anArgument
    取消所有mode中的perform select,argument必须跟指定调用时候的一样
  - (void)cancelPerformSelectorsWithTarget:(id)target
  - (NSString *)currentMode
    如果run loop没有运行,那么返回nil
  - (CFRunLoopRef)getCFRunLoop
  - (NSDate *)limitDateForMode:(NSString *)mode
    下一次运行的时间,如果没有指定的mode上没有input source,返回nil
  - (void)performSelector:(SEL)aSelector target:(id)target argument:(id)anArgument order:(NSUInteger)order modes:(NSArray *)modes
order值越低优先级越高
  - (void)removePort:(NSPort *)aPort forMode:(NSString *)mode
  - (void)run
    在default mode下无限运行loop,但是如果没有任何input source,会立即返回。手动移除所有已知的inout source并不能保证run loop停止运行,因为系统可能会添加一些input source。
  - (BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)limitDate
    运行input source一次,为指定mode的input阻塞直到date的时间。如过没有input source,立即返回并返回NO。
  - (void)runUntilDate:(NSDate *)limitDate
  如果没有input source,立即返回。否则在limitDate到来之前,不停的循环。
再详细的就看文档吧

二、RunLoopMode
NSDefaultRunLoopMode 这是大多数操作中使用的模式。
NSConnectionReplyMode 该模式用来监控NSConnection对象。你通常不需要在你的代码中使用该模式。
NSModalPanelRunLoopMode Cocoa使用该模式来标识用于modal panel(模态面板)的事件。
NSEventTracking(UITrackingRunLoopMode) Cocoa使用该模式来处理用户界面相关的事件。
NSRunLoopCommonModes 这是一组可配置的通用模式。将input sources与该模式关联则同时也将input sources与该组中的其它模式进行了关联。对于Cocoa应用,该模式缺省的包含了default,modal以及event tracking模式。

  一个常见的问题就是,主线程中一个NSTimer添加在default mode中,当界面上有一些scroll view的滚动频繁发生导致run loop运行在UItraking mode中,从而这个timer没能如期望那般的运行。所以,我们就可以把这个timer加到NSRunLoopCommonModes中来解决(iOS中)。

三.疑团重重
来看看这张经典的图片


其中Input source是一些异步的事件,比如port,selector等,这个会让runUntilDate:跳出(当然指的是非主线程中的runloop)。Timer source是同步的,一个timer结束后,在重复时间后或者手动fire后才会再一次调用。

在来看看这张图片

它说明了用户对ui的操作实际上是一种port,会放到一个队列中传到loop,然后由loop交给主线程处理。loop就是一个循环,接受event,传递,继续。主线程是另一个循环,负责事件的处理与界面的显示。当然这两者关系复杂。

在看下面的代码

BOOL pageStillLoading = YES;
-(void)press:(id)sender
{
[(UIButton*)sender setSelected:YES];
NSLog(@"begin"); // 1
[[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:10.0]]; // 2
NSLog(@"end"); // 3

pageStillLoading = YES;
[NSThread detachNewThreadSelector:@selector(loadPageInBackground:)toTarget:self withObject:nil]; // 4
while (pageStillLoading) {
[[NSRunLoop currentRunLoop] runMode:UITrackingRunLoopMode beforeDate:[NSDate distantFuture]]; // 5
NSLog(@"while end");
}
NSLog(@"over");

}

-(void)loadPageInBackground:(id)sender
{
sleep(3); // 6
NSLog(@"timer"); // 7
pageStillLoading = NO; // 8
}

 

我在viewcontroller的view上加了一个uibutton,并且事件是press。touch up inside,然后,不在碰触界面(A)。发生了什么?
看看log:

2013-01-06 00:57:21.167 runloop[10146:c07] begin
2013-01-06 00:57:31.171 runloop[10146:c07] end
2013-01-06 00:57:34.173 runloop[10146:3703] timer
2013-01-06 00:58:00.001 runloop[10146:c07] while end
2013-01-06 00:58:00.002 runloop[10146:c07] over


pageStillLoading设置成NO之后过了近30s,while才结束。
如果我把5的mode改成NSRunLoopCommonModes或者在界面上在加一个按钮,然后不停的点击那个按钮(B),结果如下

2013-01-06 01:01:23.944 runloop[10174:c07] begin
2013-
    
[2]WP8中 ListBox x下拉刷新 以及 ScrollViewer/ListBox 的ManipulationCompleted 失效的解决方案
    来源:    发布时间: 2013-11-15

本文同步发表于 Windows Phone论坛 WPDEVN :http://www.wpdevn.com/showtopic-138.aspx

今天在做 Wp8  中的ListBox 下拉刷新 发现一个蛋疼的问题 ManipulationCompleted   失效 这个事件死活不会触发 。。。  

没有 MainpulationComplated 手势探测就很蛋疼了 (别告诉我用gestures的toolkit 那样做就恶心了。。。。 )

 

折腾了半天 发现 在ScrollViewer下的Border  handler 了MainpulationCompleted 事件  (不知道这个是不是 控件的bug 。。。 囧)

 

那么既然 ScrollViewer 中拿不到事件 那我就再他下面去取事件吧 。。

 

直接上代码。。 具体的解释 在代码里面, 具体的说明自己看注释把。。。 

 

public class ScrollBehavior :Behavior<ListBox>
{
public event EventHandler<ScrollEventArgs> OnScroll;

private ScrollContentPresenter _scrollContentPresenter;

private ScrollViewer _scrollViewer;



protected override void OnAttached()
{

base.OnAttached();

this.AssociatedObject.LayoutUpdated += (sender, e) =>
{
if (_scrollContentPresenter == null)
{
            // 获取ListBox 中的 ListBox中的 ScrollViewer 以便获取当前滚动位置
_scrollViewer = FindChildOfType<ScrollViewer>(this.AssociatedObject,
obj =>
{
return true;
});

if (_scrollViewer == null) { return; }

            //获取ScrollViewer 中的ContentPresenter 用来订阅ManipulationCompleted 事件,之所以不取Handle住事件Border 是考虑到 ScrollView 有可能被定制 里面就可能不止一个 Border
            //而ContentPresenter 是在border 下面的 事件可以正常捕获 而且 在ScrollViwer 中 ContentPresenter 是唯一的。

_scrollContentPresenter = FindChildOfType<ScrollContentPresenter>(_scrollViewer,
obj =>
{
return true;
});

if (_scrollContentPresenter != null)
{

Logger.LogMessage("Event handler attched");
              // 订阅事件 获取手势结束时的坐标
_scrollContentPresenter.ManipulationCompleted += OnManipulationCompleted;
              // 订阅事件 获取手势开始时的坐标
// 注意:这里之所以不订阅 MainpulationStart事件 是因为 该事件给出的坐标是在点击位置 所在控件中的相对坐标
// 比如手势开始时点击位置是在ListBox 中 第三个ITem 中的一个图片上 那么给出坐标是这个图片中的相对坐标而非ScrollViewer的
// 而 ManipulationCopleted 给出的坐标是ScrollViewer的相对坐标 。。 坐标系不统一很蛋疼的。
_scrollContentPresenter.MouseLeftButtonDown += OnMouseLeftButtonDown;

}
}
};
base.OnAttached();
}

System.Windows.Input.MouseButtonEventArgs _buttonDownArgs;

void OnMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
_buttonDownArgs = e;
}


void OnManipulationCompleted(object sender, System.Windows.Input.ManipulationCompletedEventArgs e)
{
double delta = e.ManipulationOrigin.Y - _buttonDownArgs.GetPosition(e.ManipulationContainer).Y;/这就是通过MouseLeftButtonDown 获取到坐标的好处,直接统一了坐标系:)

       //下面就就是判断手势位置什么的了 我就不解释。。。  ScrollEventArgs 这些我自己定义的参数类 大家就不要在意啦。。。
if ( _scrollViewer.ScrollableHeight == _scrollViewer.ScrollableHeight && delta <-100)
{
FireOnScroll(new ScrollEventArgs(ScrollState.Bottom));
}
else if (_scrollViewer.VerticalOffset ==0 && delta > 100)
{
FireOnScroll(new ScrollEventArgs(ScrollState.Top));

}
}

void FireOnScroll(ScrollEventArgs args)
{
if (OnScroll != null)
{
OnScroll(_scrollViewer, args);
}
}



static T FindChildOfType<T>(DependencyObject root, Func<T, bool> verifyFunc) where T : class
{
var queue = new Queue<DependencyObject>();
queue.Enqueue(root);

while (queue.Count > 0)
{
DependencyObject current = queue.Dequeue();
for (int i = VisualTreeHelper.GetChildrenCount(current) - 1; 0 <= i; i--)
{
var child = VisualTreeHelper.GetChild(current, i);
var typedChild = child as T;
if (typedChild != null)
{
if (verifyFunc(typedChild))
return typedChild;
}
queue.Enqueue(child);

    
[3]android 自定义RadioButton(单选按钮)图标随便定.
    来源: 互联网  发布时间: 2013-11-15
RadioButton在我们开发APP应用中是很常见的.这点我不用说大家也心知肚明.
        虽说Android 系统给我们提供了RadioButton但是为了我们的应用有种"与众不同"的效果,因为android的太死板太斯通见惯了.往往都会定制自己的图标.下面我给大家介绍一下我实现的方法:
        方法:运用组合控件(ImageView and TextView)
      组合控件代码: /***
* 组合控件
*
* @author zhangjia
*
*/
public class RadioButton extends LinearLayout {
private Context context;
private ImageView imageView;
private TextView textView;

private int index = 0;
private int id = 0;// 判断是否选中

private RadioButton tempRadioButton;// 模版用于保存上次点击的对象

private int state[] = { R.drawable.radio_unchecked,
   R.drawable.radio_checked };


/***
  * 改变图片
  */
public void ChageImage() {

  index++;
  id = index % 2;// 获取图片id
  imageView.setImageResource(state[id]);
}

/***
  * 设置文本
  *
  * @param text
  */
public void setText(String text) {
  textView.setText(text);
}

public String getText() {
  return id == 0 ? "" : textView.getText().toString();

}

public RadioButton(Context context) {
  this(context, null);

}

public RadioButton(Context context, AttributeSet attrs) {
  super(context, attrs);
  this.context = context;
  LayoutInflater.from(context).inflate(R.layout.item, this, true);
  imageView = (ImageView) findViewById(R.id.iv_item);
  textView = (TextView) findViewById(R.id.tv_item);

}

}
上面的实现的很容易,所以不过多解释.
 
  下面是调用代码:
  public class MainActivity extends Activity {
ListView listView;

@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  listView = (ListView) findViewById(R.id.lv_main);
  listView.setAdapter(new MyAdapter(this));
}

/***
  * @author jia
  */
RadioButton temp;

class MyAdapter extends BaseAdapter {
  private Context context;
  private LayoutInflater inflater;

  public MyAdapter(Context context) {
   super();
   this.context = context;
   inflater = LayoutInflater.from(context);
  }

  @Override
  public int getCount() {
   return 10;
  }

  @Override
  public Object getItem(int position) {
   return null;
  }

  @Override
  public long getItemId(int position) {
   return 0;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
   final RadioButton radioButton;
   if (convertView == null) {
    radioButton = new RadioButton(context);
   } else {
    radioButton = (RadioButton) convertView;
   }

   radioButton.setText(position + "");

   radioButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
     // 模版不为空,则chage.
     if (temp != null) {
      temp.ChageImage();
     }
     temp = radioButton;
     radioButton.ChageImage();

     Toast.makeText(context, radioButton.getText(), 1000).show();

    }
   });

   return radioButton;
  }
}
}我来说明一下:我们首先创建一个temp模版,用于记忆你点击的那个RadioButton对象.  在你点击时候,首先查看temp是否为null,如果不为空则执行 temp.ChageImage(); 这个方法是取消选中效果.如果不为null,则首先对该RadioButton执行,取消该按钮选中状态.在执行你点击的那个RadioButton的ChageImage方法,最后记得要把当前的RadioButton付给temp.
 
   效果:
    
9 小时前 上传
下载附件 (30.87 KB)
   
9 小时前 上传
下载附件 (32.41 KB)

  效果是实现了,不过有个小问题,因为目前只有10条数据是看不出效果的.换成20条你就会发现很诡异的问题。
  图“:
 
9 小时前 上传
下载附件 (36.45 KB)


  第15条数据会自动勾选上,找了又找,最后终于发现了,是因为listview 的问题。看下面:
  final RadioButton radioButton;
   if (convertView == null) {
    radioButton = new RadioButton(context);
   } else {
    radioButton = (RadioButton) convertView;
   }

  也许你会发现了,因为我们为了提高效率,重用了listview个convertView.所以会出现这种bug,解决方法也很简单,只需要我们把上面代码更换为
  final RadioButton radioButton;
    radioButton = new RadioButton(context);
  
  虽说这样效率有点低,但是有时候我们需要则断一下,只要能实现效果,偶尔对性能放下水也是OK的,何况这种情况下不可能有那么多列.
 

   项目实现样式:
       
9 小时前 上传
下载附件 (70.04 KB)
     
9 小时前 上传
下载附件 (71.5 KB)

      看起来还凑合吧。
 
  这里我把代码上传一下,不足的地方,自己可以进行调整,我只是提供个思路.
       源码下载
  [color=ize:18px]

  [color=ize:18px]额外拓展:
  [color=ize:18px]/*****************************************************************************/
  [color=ize:18px]LayoutInflater.from(context).inflate(R.layout.item, this);

  [color=ize:18px]View view=LayoutInflater.from(context).inflate(R.
    
最新技术文章:
 




特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3