Android列表视图设置选择和滚动到位置

时间:2015-04-08 18:10:45

标签: android listview android-listview

我将失去对ListView的最后耐心。似乎任何人都没有想到我的场景:

  1. 该列表在活动布局上有大约5个可见行
  2. 列表应滚动按钮:"Down" - 用于选择下一个项目。 "Up"用于选择之前的内容。
  3. 所选项目必须可见。如果可能在视图中居中。这意味着当按下向上/向下按钮时,列表将滚动并且项目将保持不变。
  4. 我已经拥有的东西:

    1. 包含adapter的列表,以及使用
      工作的选择器drawable listview.getChildAt( index ).setSelected( true );
    2. 滚动列表的一种不太可靠的方法:使用:
      smoothScrollToPositionFromTop( mCurSel, 0, 100 );
    3. 它不可靠,因为一旦它到达没有标准高度的项目(而不是列表中的其他项目),它就会开始搞乱选择/滚动并且到达列表开始表现得非常奇怪的点。 / p>

      现在,有没有可以做我想要的替代品(准备好,开源)?我即将重新编写该列表没有 ListView。

2 个答案:

答案 0 :(得分:2)

也许它可能适用于ListView,但不是很容易..无论如何,如果使用v7支持包中的RecyclerView,那么这里有一个很好的帖子如何做我想要的:

tracking-selected-item-in-recyclerview

如此回答:

how-to-properly-highlight-selected-item-on-recyclerview

只是为了节省时间让任何人试图做这个简单而又如此复杂的尝试来获得一个合理的选择工作正常...这是基本的,这里是我的解释:

  1. 获取"支持v7"使用SDK管理器打包。

  2. 如果在Android Studio中工作,将v7 jar添加到项目中应该是轻而易举的事情,日食就像在火上行走并同时喝酸(完全没有乐趣) - 到简而言之:从sdk存储库复制以下jar:

  3. 一个。 sdk /.../ extra / ... v4 / android-support-v4.jar到" libs"下的项目, 湾对sdk /.../ extra / ... v7 / ..执行相同的操作.RelalerlerView / recyclerview-v7-22.0.0.jar c。和sdk /.../ extra / ... v7 / .. CardView / cardview-v7-22.0.0.jar d。将sdk /.../ extra / ... v7 / ..将CardView / values.xml合并到项目的values.xml

    到此为止 - 只需将RecyclerView添加到您的项目......嗯......这么多工作! ;)我正在为你节省研究时间......

    注意:布局编辑器无法识别RecyclerView,因此您必须手动添加它(并且它将继续大声说这是一个糟糕的类... bla bla bla)

    1. 主要活动布局:
    2. 
      
      	<?xml version="1.0" encoding="utf-8"?>
      	<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      	    xmlns:tools="http://schemas.android.com/tools"
      	    android:layout_width="match_parent"
      	    android:layout_height="match_parent"
      	    android:paddingBottom="@dimen/activity_vertical_margin"
      	    android:paddingLeft="@dimen/activity_horizontal_margin"
      	    android:paddingRight="@dimen/activity_horizontal_margin"
      	    android:paddingTop="@dimen/activity_vertical_margin"
      	    tools:context="com.example.listtester.MainActivity" >
      	
      	    <android.support.v7.widget.RecyclerView
      	        android:id="@+id/my_recycler_view"
      	        android:layout_width="match_parent"
      	        android:layout_height="match_parent"
      	        android:layout_above="@+id/up_button"
      	        android:scrollbars="vertical" />
      	
      	    <Button
      	        android:id="@+id/up_button"
      	        android:layout_width="wrap_content"
      	        android:layout_height="wrap_content"
      	        android:layout_alignLeft="@+id/my_recycler_view"
      	        android:layout_alignParentBottom="true"
      	        android:text="Up" />
      	
      	    <Button
      	        android:id="@+id/down_button"
      	        android:layout_width="wrap_content"
      	        android:layout_height="wrap_content"
      	        android:layout_alignParentBottom="true"
      	        android:layout_toRightOf="@+id/up_button"
      	        android:text="Down" />
      	
      	</RelativeLayout>
      &#13;
      &#13;
      &#13;

      1. 项目布局:
      2. &#13;
        &#13;
        <?xml version="1.0" encoding="utf-8"?>
        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="fill_parent"
            android:layout_height="?android:attr/listPreferredItemHeight"
            android:padding="6dip" 
            android:background="@drawable/list_item_selector">
        
            <ImageView
                android:id="@+id/icon"
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
                android:layout_alignParentBottom="true"
                android:layout_alignParentTop="true"
                android:layout_marginRight="6dip"
                android:contentDescription="TODO"
                android:src="@drawable/ic_launcher" />
        
            <TextView
                android:id="@+id/secondLine"
                android:layout_width="fill_parent"
                android:layout_height="26dip"
                android:layout_alignParentBottom="true"
                android:layout_alignParentRight="true"
                android:layout_toRightOf="@id/icon"
                android:ellipsize="marquee"
                android:singleLine="true"
                android:text="Description"
                android:textSize="12sp" />
        
            <TextView
                android:id="@+id/firstLine"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_above="@id/secondLine"
                android:layout_alignParentRight="true"
                android:layout_alignParentTop="true"
                android:layout_alignWithParentIfMissing="true"
                android:layout_toRightOf="@id/icon"
                android:gravity="center_vertical"
                android:text="Example application"
                android:textSize="16sp" />
        
        </RelativeLayout> 
        &#13;
        &#13;
        &#13;

        1. 将colors.xml添加到res / values文件夹
        2. &#13;
          &#13;
          <?xml version="1.0" encoding="utf-8"?>
          <resources>
              <color name="pressed_color">#ffffff00</color>
              <color name="default_color">#ffffffff</color>
              
          </resources>
          &#13;
          &#13;
          &#13;

          1. 添加list_item_drawable.xml
          2. &#13;
            &#13;
            <?xml version="1.0" encoding="utf-8" ?>
            <selector xmlns:android="http://schemas.android.com/apk/res/android">
                <item 
                    android:state_selected="true"
                    android:drawable="@color/pressed_color"/>
                <item
                    android:drawable="@color/default_color" />
            </selector>
            &#13;
            &#13;
            &#13;

            1. MainActivity.java
            2. &#13;
              &#13;
              package com.example.listtester;
              
              import java.util.ArrayList;
              import android.app.Activity;
              import android.os.Bundle;
              import android.support.v7.widget.LinearLayoutManager;
              import android.support.v7.widget.RecyclerView;
              import android.view.Menu;
              import android.view.MenuItem;
              import android.view.View;
              import android.view.View.OnClickListener;
              import android.widget.Button;
              import android.widget.TextView;
              
              public class MainActivity extends Activity
              {
              	private RecyclerView				mRecyclerView;
              	private MyAdapter					mAdapter;
              	private RecyclerView.LayoutManager	mLayoutManager;
              
              	public static class ViewHolder extends RecyclerView.ViewHolder
              	{
              		// each data item is just a string in this case
              		public TextView	txtHeader;
              		public TextView	txtFooter;
              
              		public ViewHolder( View v )
              		{
              			super( v );
              			txtHeader = (TextView)v.findViewById( R.id.firstLine );
              			txtFooter = (TextView)v.findViewById( R.id.secondLine );
              		}
              	}
              
              	@Override
              	protected void onCreate( Bundle savedInstanceState )
              	{
              		super.onCreate( savedInstanceState );
              		setContentView( R.layout.activity_main );
              		mRecyclerView = (RecyclerView)findViewById( R.id.my_recycler_view );
              
              		// use this setting to improve performance if you know that changes
              		// in content do not change the layout size of the RecyclerView
              		mRecyclerView.setHasFixedSize( true );
              
              		// use a linear layout manager
              		mLayoutManager = new LinearLayoutManager( this );
              		mRecyclerView.setLayoutManager( mLayoutManager );
              
              		// specify an adapter (see also next example)
              		ArrayList<String> myDataset = new ArrayList<String>();
              		myDataset.add( "1234" );
              		myDataset.add( "adsf" );
              		myDataset.add( "2344" );
              		myDataset.add( "1234" );
              		myDataset.add( "32456344" );
              		myDataset.add( "12356564" );
              		myDataset.add( "1dfsdg234" );
              		myDataset.add( "1234" );
              		myDataset.add( "32456344" );
              		myDataset.add( "12356564" );
              		myDataset.add( "1dfsdg234" );
              		myDataset.add( "1234" );
              		myDataset.add( "32456344" );
              		myDataset.add( "12356564" );
              		myDataset.add( "1dfsdg234" );
              		mAdapter = new MyAdapter( myDataset );
              		mRecyclerView.setAdapter( mAdapter );
              
              		Button up = (Button)findViewById( R.id.up_button );
              		up.setOnClickListener( new OnClickListener()
              		{
              			@Override
              			public void onClick( View v )
              			{
              				mAdapter.scrollUp();
              			}
              		} );
              
              		Button down = (Button)findViewById( R.id.down_button );
              		down.setOnClickListener( new OnClickListener()
              		{
              			@Override
              			public void onClick( View v )
              			{
              				mAdapter.scrollDown();
              			}
              		} );
              	}
              
              	@Override
              	public boolean onCreateOptionsMenu( Menu menu )
              	{
              		// Inflate the menu; this adds items to the action bar if it is present.
              		getMenuInflater().inflate( R.menu.main, menu );
              		return true;
              	}
              
              	@Override
              	public boolean onOptionsItemSelected( MenuItem item )
              	{
              		// Handle action bar item clicks here. The action bar will
              		// automatically handle clicks on the Home/Up button, so long
              		// as you specify a parent activity in AndroidManifest.xml.
              		int id = item.getItemId();
              		if( id == R.id.action_settings )
              		{
              			return true;
              		}
              		return super.onOptionsItemSelected( item );
              	}
              }
              &#13;
              &#13;
              &#13;

              1. MyAdapter.java
              2. &#13;
                &#13;
                package com.example.listtester;
                
                import java.util.ArrayList;
                import android.support.v7.widget.RecyclerView;
                import android.view.KeyEvent;
                import android.view.LayoutInflater;
                import android.view.View;
                import android.view.View.OnClickListener;
                import android.view.ViewGroup;
                import android.widget.TextView;
                
                public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>
                {
                	private ArrayList<String>	mDataset;
                	private int					mSelectedItem	= 0;
                	private RecyclerView		mRecyclerView;
                
                	// Provide a reference to the views for each data item
                	// Complex data items may need more than one view per item, and
                	// you provide access to all the views for a data item in a view holder
                	public class ViewHolder extends RecyclerView.ViewHolder
                	{
                		// each data item is just a string in this case
                		public TextView	txtHeader;
                		public TextView	txtFooter;
                
                		public ViewHolder( View v )
                		{
                			super( v );
                			txtHeader = (TextView)v.findViewById( R.id.firstLine );
                			txtFooter = (TextView)v.findViewById( R.id.secondLine );
                
                			// Handle item click and set the selection
                			itemView.setClickable( true );
                			itemView.setOnClickListener( new View.OnClickListener()
                			{
                				@Override
                				public void onClick( View v )
                				{
                					// Redraw the old selection and the new
                					notifyItemChanged( mSelectedItem );
                					mSelectedItem = mRecyclerView.getChildAdapterPosition( v );
                					notifyItemChanged( mSelectedItem );
                				}
                			} );
                		}
                	}
                	
                	public void scrollUp()
                	{
                		RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager();
                		tryMoveSelection( lm, -1 );
                	}
                	
                	public void scrollDown()
                	{
                		RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager();
                		tryMoveSelection( lm, 1 );
                	}
                
                	@Override
                	public void onAttachedToRecyclerView( final RecyclerView recyclerView )
                	{
                		super.onAttachedToRecyclerView( recyclerView );
                		mRecyclerView = recyclerView;
                	}
                
                	private boolean tryMoveSelection( RecyclerView.LayoutManager lm, int direction )
                	{
                		int nextSelectItem = mSelectedItem + direction;
                
                		// If still within valid bounds, move the selection, notify to redraw,
                		// and scroll
                		if( nextSelectItem >= 0 && nextSelectItem < getItemCount() )
                		{
                			notifyItemChanged( mSelectedItem );
                			mSelectedItem = nextSelectItem;
                			notifyItemChanged( mSelectedItem );
                			lm.scrollToPosition( mSelectedItem );
                			return true;
                		}
                
                		return false;
                	}
                
                	public void add( int position, String item )
                	{
                		mDataset.add( position, item );
                		notifyItemInserted( position );
                	}
                
                	public void remove( String item )
                	{
                		int position = mDataset.indexOf( item );
                		mDataset.remove( position );
                		notifyItemRemoved( position );
                	}
                
                	// Provide a suitable constructor (depends on the kind of dataset)
                	public MyAdapter( ArrayList<String> myDataset )
                	{
                		mDataset = myDataset;
                	}
                
                	// Create new views (invoked by the layout manager)
                	@Override
                	public MyAdapter.ViewHolder onCreateViewHolder( ViewGroup parent,
                			int viewType )
                	{
                		// create a new view
                		View v = LayoutInflater.from( parent.getContext() ).inflate(
                				R.layout.item_layout, parent, false );
                		// set the view's size, margins, paddings and layout parameters
                		ViewHolder vh = new ViewHolder( v );
                		return vh;
                	}
                
                	// Replace the contents of a view (invoked by the layout manager)
                	@Override
                	public void onBindViewHolder( ViewHolder holder, int position )
                	{
                		// - get element from your dataset at this position
                		// - replace the contents of the view with that element
                		final String name = mDataset.get( position );
                		holder.txtHeader.setText( mDataset.get( position ) );
                //		holder.txtHeader.setOnClickListener( new OnClickListener()
                //		{
                //			@Override
                //			public void onClick( View v )
                //			{
                //				remove( name );
                //			}
                //		} );
                
                		holder.txtFooter.setText( "Footer: " + mDataset.get( position ) );
                		holder.itemView.setSelected( mSelectedItem == position );
                
                	}
                
                	// Return the size of your dataset (invoked by the layout manager)
                	@Override
                	public int getItemCount()
                	{
                		return mDataset.size();
                	}
                
                }
                &#13;
                &#13;
                &#13;

                为了实现这个非常基本的选择,我去了这么长而且令人沮丧的jurney(更不用说在项目中添加recyclerview了......)希望它可以帮到某个人。

答案 1 :(得分:1)

如果我理解正确,您想要滚动到正确的位置。在滚动时获取正确的行位置(在ListView中)的问题具有固有的计时问题。在任何时间点,我们都需要确定哪些行位置是可见的。我使用了监听器setOnScrollListener。 示例代码:

listview.setOnScrollListener(new AbsListView.OnScrollListener() {
   @Override
   public void onScrollStateChanged(AbsListView view, int scrollState) {
                }

   @Override
   public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
      topVisiblePosition = firstVisibleItem;
      ...
   }

稍后......

listview.setSelection(topVisiblePosition);

注意:

  • 我没有注意到使用onScroll侦听器方法的任何性能延迟。
  • setSelection方法对我来说已经足够了。
  • 变量 topVisiblePosition 保存在类中,与 setSelection 方法一起使用。
  • onScroll覆盖方法包含有用的信息,例如visibleItemCount及其总计数,最适合确定最后一个可见行。