30879


Visual Studio2015+xamarinで、Androidアプリを制作しています。

・タップ時にカウントを1増やす  
・長押し時、ボタンに触れた段階でカウントを1増やす 1秒間、間を置いてタップしている間カウントを0.1秒ずつ1増やす  
・長押し時、指を離すと止まる

というボタンを作成しようとしていますが、条件の2つめと３つめの処理をどのように作成すべきかわからず困っています。  
現在、LongClickを使用し、長押しの状態を認識させていますが、  
長押しした後にカウントが１増えるだけの状態です。  
今回作成しようとしているボタンを作るにはどのように改善していけばよいでしょうか？

コードは以下の通りです

[code]

    using System;
    using Android.App;
    using Android.Content;
    using Android.Runtime;
    using Android.Views;
    using Android.Widget;
    using Android.OS;
    
    namespace test
    {
    [Activity(Label = "test", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : BaseActivity
    {
    
        protected override int LayoutResource
        {
            get { return Resource.Layout.main; }
        }
        int count = 1;
    
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
    
            // Get our button from the layout resource,
            // and attach an event to it
            var clickButton = FindViewById<Button>(Resource.Id.my_button);
    
            clickButton.Click += (sender, args) =>
              {
                  clickButton.Text = string.Format("{0} clicks!", count++);
              };
            clickButton.LongClick += (sender, args) =>
            {
                clickButton.Text = string.Format("{0} clicks!", count++);
            };
    
    
            var navigationButton = FindViewById<Button>(Resource.Id.nav_button);
    
            navigationButton.Click += (sender, args) =>
              {
                  var intent = new Intent(this, typeof(SecondActivity));
                  intent.PutExtra("clicks", count);
                  StartActivity(intent);
              };
    
    
    
            SupportActionBar.SetDisplayHomeAsUpEnabled(false);
            SupportActionBar.SetHomeButtonEnabled(false);
    
        }
    }
    }
    
[/code]

# 追記

ありがとうございます。  
だいぶ期間が空いてしまいましたが、教えていただいたページと流れを参考にontouchを使用して動作させています。  
現在、作成したコード内容は以下の通りです。  
while文を使用し、ボタンが押しっぱなしになっている時にカウントアップし、ボタンから離すと止まるようにしたいのですが、ボタンから手を離してもMotionEventActions.Downの状態が認識され続けて無限ループが発生してしまいます。  
どのようにすればループから抜け出すことができますか？

[code]

    using Android.App;
    using Android.Widget;
    using Android.OS;
    using Android.Views;
    using System.Diagnostics;
    
    namespace test2
    {
    [Activity(Label = "test2", MainLauncher = true, Icon = "@mipmap/icon")]
    public class MainActivity : Activity, View.IOnTouchListener
    {
    
        Stopwatch stopwatch = new Stopwatch();
        int count = 1;
        private Button button;
        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
    
            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);
    
            // Get our button from the layout resource,
            // and attach an event to it
            button = FindViewById<Button>(Resource.Id.myButton);
    
            button.SetOnTouchListener(this);
    
        }
        public bool OnTouch(View v, MotionEvent e)
        {
            switch (e.Action)
            {
                case MotionEventActions.Down:
                    stopwatch.Start();
                    button.Text = string.Format("{0} clicks!", count++);
                    break;
    
                case MotionEventActions.Up:
    
                    Toast.MakeText(this, "up", ToastLength.Long).Show();
                    stopwatch.Stop();
                    stopwatch.Reset();
                    break;
    
    
            }
    
            Toast.MakeText(this, "root", ToastLength.Long).Show();
            while (e.Action == MotionEventActions.Down)
            {
                if (stopwatch.ElapsedMilliseconds > 1000)
                {
                    if (stopwatch.ElapsedMilliseconds % 100 == 0)
                    {
                        button.Text = string.Format("{0} clicks!", count++);
                    }
                }
    
            }
            return true;
        }
    }
    
    }
    
[/code]


CC BY-SA 3.0
2016-10-29T11:00:07.913
29984
2016-12-04T05:30:47.263
2016-11-29T10:53:14.387
18536
18536
question
android c# xamarin xamarin-native
xamarinのボタン長押しイベントの作成方法


おそらく作成されたいのは、

  * 普通にポチポチ押すと、押した数だけ +1 される
  * ずっと押していると、押している間、素早く +1 され続ける

ボタンかと思います。

> 現在、LongClickを使用し、長押しの状態を認識させていますが、

だと、これ自体が「ボタンを離した」ときに発生するので、「押している」ことを検知できないと思います。

この場合、View の onTouchEvent を使って、自力で「長押し開始」〜「長押し終了」をコーディングする必要があるように思います。

  * [ボタンが押されると.... - Androidプログラマへの道 ～ Moonlight 明日香 ～](http://seesaawiki.jp/w/moonlight_aska/d/%A5%DC%A5%BF%A5%F3%A4%AC%B2%A1%A4%B5%A4%EC%A4%EB%A4%C8....)

は Java での Android アプリ開発Tipsですが、参考になります。

具体的には、指を触れると ACTION_DOWN が、指を離すと ACTION_UP が発生するので、「長押し」を表現するには、

  1. ACTION_DOWN で長押し検知用タイマーを起動する
  2. 長押し検知用タイマーが１秒間経過したら、カウントアップ用タイマーを起動し、0.1秒毎に +1 させる
  3. ACTION_UP で 長押し検知用タイマー と カウントアップ用タイマー を停止する

となると思います。  
ただし、上の手順以外に「2. よりも先に ACTION_UP が来た場合」など、考慮することが多いので、複雑なプログラムになるのではと思います。

再度になりますが、この要件を満たしたい場合は、 Click イベントも、 LongClick イベントも使えず、すべて onTouchEvent
イベントを使う必要があると思います。


CC BY-SA 3.0
2016-10-30T08:25:18.810
29993
2016-10-30T08:25:18.810
15190
29984
answer


`OnTouch()`
はボタンを押した時(MotionEventActions.Down)と、離した時(MotionEventActions.Up)で別々に呼ばれます。

つまり、1回の呼び出しの中でe.Actionの値が変更されることは無いため、 `while (e.Action ==
MotionEventActions.Down)` を抜けることはありません。カウントが止まらなくなるのはそのためです。

ループは別スレッドに追い出し、タッチイベントではスレッドの起動・キャンセルを行うと良いでしょう。

[code]

    System.Threading.CancellationTokenSource cancellationTokenSource;
    
    public bool OnTouch(View v, MotionEvent e)
    {
        var textView = FindViewById<TextView>(Resource.Id.text);
    
        switch (e.Action)
        {
            case MotionEventActions.Down:
                textView.Text = string.Format("{0} clicks!", count++);
                if (cancellationTokenSource != null)
                    break;
    
                cancellationTokenSource = new System.Threading.CancellationTokenSource();
                var token = cancellationTokenSource.Token;
    
                // whileループは別スレッドで回す
                System.Threading.Tasks.Task.Factory.StartNew(() =>
                {
                    var stopwatch = Stopwatch.StartNew();
                    while(stopwatch.ElapsedMilliseconds < 1000 &&
                            token.IsCancellationRequested == false)
                    {
                        System.Threading.Tasks.Task.Delay(TimeSpan.FromMilliseconds(10)).Wait();
                    }
    
                    while (token.IsCancellationRequested == false)
                    {
                        // カウント表示の更新はUIスレッドから行う必要がある
                        RunOnUiThread(() => {
                            textView.Text = string.Format("{0} clicks!", count++);
                        });
                        System.Threading.Tasks.Task.Delay(TimeSpan.FromMilliseconds(100)).Wait();
                    }
                }, token)
                .ContinueWith(_ =>
                {
                    // 後始末
                    cancellationTokenSource.Dispose();
                    cancellationTokenSource = null;
                });
                break;
            case MotionEventActions.Up:
                if (cancellationTokenSource != null)
                {
                    cancellationTokenSource.Cancel();
                }
                break;
        }
    
        return true;
    }
    
[/code]


CC BY-SA 3.0
2016-12-04T05:30:47.263
30879
2016-12-04T05:30:47.263
3022
29984
answer