web-dev-qa-db-ja.com

Androidで水平ListViewを作成するにはどうすればよいですか?

可能性のある複製:
Androidの水平リストビュー?

Androidの多くのことと同様に、これはそれほど難しい問題ではないと思いますが、まあ、あなたは間違っているでしょう。また、Androidの多くのものと同様に、APIは合理的に拡張可能な開始点すら提供していません。私が自分のListViewをロールバックするつもりなら、私はそのことを取り、それを横に向けるだけです。\rant

さて、発煙が終わったので、問題自体について話しましょう。必要なのは、基本的にGalleryに似たものですが、センターロック機能はありません。 ListViewのlistSelectorは実際には必要ありませんが、持っているのがいいです。ほとんどの場合、LinearLayout内でScrollViewを使用して必要な処理を実行できますが、ListAdapterから子ビューを取得する必要があり、ビューリサイクラが必要です。そして、私は本当にレイアウトコードを書きたくない。

私はこれらのクラスのいくつかのソースコードを覗きました...

Gallery: 'onXyz'メソッドのほとんどをオーバーライドし、すべてのソースコードをコピーするが、scrollIntoSlots()の呼び出しを控えると、ギャラリーを使用できるように見えます。しかし、それを行うと、アクセスできないメンバーフィールドや、その他の予期しない結果が発生することになります。

AbsSpinner:mRecyclerフィールドはパッケージプライベートなので、このクラスを拡張できるとは思えません。

AbsListView:このクラスは垂直スクロールのみを目的としているように見えるため、そこでは何の助けもありません。

AdapterView:このクラスを直接拡張する必要はありませんでした。あなたがそれをするのは簡単で、自分のRecycleBinを転がすのは簡単だと言ったら、私は非常に懐疑的ですが、試してみます。

おそらくbothAbsSpinnerGalleryをコピーして、必要なものを取得できると思います。 。それは良い習慣だと思いますか?誰かが私を正しい方向に導くチュートリアルやサードパーティのソリューションを持っていますか?

更新:
これまでに見つけた唯一の解決策は、すべて自分でやることです。この質問をしてから、AdapterViewをオーバーライドし、独自の "Horizo​​ntalListView"をゼロから実装しました。ギャラリーのセンターロック機能を本当にオーバーライドする唯一の方法は、プライベートscrollIntoSlotsメソッドをオーバーライドすることです。これは、実行時にサブクラスを生成する必要があると思います。あなたがそれをするのに十分大胆であれば、それは間違いなく最良の解決策ですが、私は変更される可能性のある文書化されていない方法に依存したくありません。

以下のSwathi EPは、GalleryOnTouchListenerを指定し、スクロール機能をオーバーライドすることを提案しました。リストでフリングをサポートすることを気にしない場合、またはフリングアニメーションの最後でビューが中央にスナップしても問題ない場合、これはwillに役立ちます。ただし、最終的には、フリングサポートを削除せずにセンターロック機能を削除することは不可能であることが判明しています。そして、私はあなたに尋ねます、どんな種類のリストが投げかけられませんか?

悲しいかな、これは私にはうまくいきませんでした。 :-(ただし、このアプローチに興味がある場合は、続きを読んでください...

また、Swathiのコードにいくつか追加して、必要なものを取得する必要がありました。 GestureListener.onTouchでは、ジェスチャ検出器への委任に加えて、ACTION_UPおよびACTION_CANCELイベントに対してもtrueを返す必要がありました。これにより、センターロック機能が正常に無効になりましたが、フリングも無効になりました。自分のGestureListenerをギャラリーのonFlingメソッドに委任することで、フリングを再度有効にすることができました。試してみたい場合は、ApiDemosサンプルコードに移動し、Gallery1.Javaクラスを次のコードに置き換えます。

import com.example.Android.apis.R;

import Android.app.Activity;
import Android.content.Context;
import Android.content.res.TypedArray;
import Android.os.Bundle;
import Android.view.ContextMenu;
import Android.view.GestureDetector;
import Android.view.MenuItem;
import Android.view.MotionEvent;
import Android.view.View;
import Android.view.ViewGroup;
import Android.view.ContextMenu.ContextMenuInfo;
import Android.view.GestureDetector.SimpleOnGestureListener;
import Android.view.View.OnTouchListener;
import Android.widget.AdapterView;
import Android.widget.BaseAdapter;
import Android.widget.Gallery;
import Android.widget.ImageView;
import Android.widget.Toast;
import Android.widget.AdapterView.AdapterContextMenuInfo;
import Android.widget.AdapterView.OnItemClickListener;

public class Gallery1 extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.gallery_1);

        // Reference the Gallery view
        final Gallery g = (Gallery) findViewById(R.id.gallery);

        // Set the adapter to our custom adapter (below)
        g.setAdapter(new ImageAdapter(this));

        // Set a item click listener, and just Toast the clicked position
        g.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView parent, View v, int position, long id) {
                Toast.makeText(Gallery1.this, "" + position, Toast.LENGTH_SHORT).show();
            }
        });

        // Gesture detection
        final GestureDetector gestureDetector = new GestureDetector(new MyGestureDetector(g));
        OnTouchListener gestureListener = new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                boolean retVal = gestureDetector.onTouchEvent(event);
                int action = event.getAction();
                if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
                    retVal = true;
                    onUp();
                }
                return retVal;
            }

            public void onUp() {
                // Here I am merely copying the Gallery's onUp() method.
                for (int i = g.getChildCount() - 1; i >= 0; i--) {
                    g.getChildAt(i).setPressed(false);
                }
                g.setPressed(false);
            }
        };
        g.setOnTouchListener(gestureListener);

        // We also want to show context menu for longpressed items in the gallery
        registerForContextMenu(g);
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        menu.add(R.string.gallery_2_text);
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
        Toast.makeText(this, "Longpress: " + info.position, Toast.LENGTH_SHORT).show();
        return true;
    }

    public class ImageAdapter extends BaseAdapter {
        int mGalleryItemBackground;

        public ImageAdapter(Context c) {
            mContext = c;
            // See res/values/attrs.xml for the <declare-styleable> that defines
            // Gallery1.
            TypedArray a = obtainStyledAttributes(R.styleable.Gallery1);
            mGalleryItemBackground = a.getResourceId(
                    R.styleable.Gallery1_Android_galleryItemBackground, 0);
            a.recycle();
        }

        public int getCount() {
            return mImageIds.length;
        }

        public Object getItem(int position) {
            return position;
        }

        public long getItemId(int position) {
            return position;
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            ImageView i = new ImageView(mContext);

            i.setImageResource(mImageIds[position]);
            i.setScaleType(ImageView.ScaleType.FIT_XY);
            i.setLayoutParams(new Gallery.LayoutParams(136, 88));

            // The preferred Gallery item background
            i.setBackgroundResource(mGalleryItemBackground);

            return i;
        }

        private Context mContext;

        private Integer[] mImageIds = {
                R.drawable.gallery_photo_1,
                R.drawable.gallery_photo_2,
                R.drawable.gallery_photo_3,
                R.drawable.gallery_photo_4,
                R.drawable.gallery_photo_5,
                R.drawable.gallery_photo_6,
                R.drawable.gallery_photo_7,
                R.drawable.gallery_photo_8
        };
    }

    public class MyGestureDetector extends SimpleOnGestureListener {

        private Gallery gallery;

        public MyGestureDetector(Gallery gallery) {
            this.gallery = gallery;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 
                float velocityY) {
            return gallery.onFling(e1, e2, velocityX, velocityY);
        }
    }

}
182
Neil Traft

この投稿を読んだ後、私は自分の水平ListViewを実装しました。ここで見つけることができます: http://dev-smart.com/horizo​​ntal-listview/ これが役立つかどうか教えてください。

48
Paul

Horizo​​ntalScrollView を使用してリストアイテムをラップすることを検討しましたか?これにより、各リストアイテムを水平方向にスクロールできます(そこに何を入れるかはあなた次第で、リストビューに似た動的なアイテムにすることができます)。これは、1行のアイテムの後にいる場合にのみ有効です。

12
Thira

これは非常に遅い返信かもしれませんが、私たちのために働いています。 Androidが提供する同じギャラリーを使用していますが、画面の左端がギャラリーの中心と見なされるように左マージンを調整しています。それは本当にうまくいきました。

4

mightdispatchDraw()(Canvasを90度回転させる)、onTouch()(Xを交換する、 MotionEvent座標のY)と、おそらくonMeasure()またはxでyではなくyでx.

これが実際に機能するかどうかはわかりませんが、調べるのは楽しいでしょう。 :)

4
Reuben Scratton

Pauls を使用しました(彼の answer を参照)Horizo​​ntalListviewの実装と動作は、共有してくれてありがとう!

私は彼のHorizo​​ntalListView-Classを少し変更しました(ところで、ポールはクラス名にタイプミスがあり、クラス名は「Horizo​​ntalListView」ではなく「Horizo​​ntialListView」、「i」は多すぎる)、選択時に子ビューを更新します。

UPDATE:ここで投稿したコードは間違っていたと思います。選択に問題が生じたためです(ビューのリサイクルに関係していると思います)。図面に戻る必要があります...

UPDATE 2:Ok問題が解決したため、単に「removeNonVisibleItems(dx);」とコメントしました。 「onLayout(..)」では、これはパフォーマンスを低下させると思いますが、非常に小さなリストのみを使用しているため、これは問題ではありません。

私は基本的にこのチュートリアルを使用しました ここdeveloperlife ListViewをPauls Horizo​​ntalListViewに置き換え、「永続的な」選択を可能にするために変更を加えました(クリックされる子は外観を変更し、クリックされると再びそれを元に戻します)。

私は初心者なので、おそらくコードの多くのmanyい点があります。詳細が必要な場合はお知らせください。

3
free

ギャラリーが最適なソリューションです。試しました。私は1つのメールアプリで作業していました。リストビューとして表示された受信ボックスのメールで、水平ビューが必要で、リストビューをギャラリーに変換しただけで、エラーなしで必要なすべてが正常に機能しました。スクロール効果については、ギャラリーのジェスチャーリスナーを有効にしました。この回答があなたのお役に立てば幸いです。

2
Swathi EP

ViewFlipperコンポーネントを調べましたか?たぶんそれはあなたを助けることができます。

http://developer.Android.com/reference/Android/widget/ViewFlipper.html

このコンポーネントを使用すると、2つ以上のビューの子をアタッチできます。翻訳アニメーションを追加し、ジェスチャー検出をキャプチャすると、きれいに水平にスクロールできます。

0
brent