我将失去对ListView
的最后耐心。似乎任何人都没有想到我的场景:
"Down"
- 用于选择下一个项目。 "Up"
用于选择之前的内容。 我已经拥有的东西:
adapter
的列表,以及使用drawable
listview.getChildAt( index ).setSelected( true );
smoothScrollToPositionFromTop( mCurSel, 0, 100 );
它不可靠,因为一旦它到达没有标准高度的项目(而不是列表中的其他项目),它就会开始搞乱选择/滚动并且到达列表开始表现得非常奇怪的点。 / p>
现在,有没有可以做我想要的替代品(准备好,开源)?我即将重新编写该列表没有 ListView。
答案 0 :(得分:2)
也许它可能适用于ListView,但不是很容易..无论如何,如果使用v7支持包中的RecyclerView,那么这里有一个很好的帖子如何做我想要的:
tracking-selected-item-in-recyclerview
如此回答:
how-to-properly-highlight-selected-item-on-recyclerview
只是为了节省时间让任何人试图做这个简单而又如此复杂的尝试来获得一个合理的选择工作正常...这是基本的,这里是我的解释:
获取"支持v7"使用SDK管理器打包。
如果在Android Studio中工作,将v7 jar添加到项目中应该是轻而易举的事情,日食就像在火上行走并同时喝酸(完全没有乐趣) - 到简而言之:从sdk存储库复制以下jar:
一个。 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)
<?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;
<?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;
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="pressed_color">#ffffff00</color>
<color name="default_color">#ffffffff</color>
</resources>
&#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;
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;
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;
为了实现这个非常基本的选择,我去了这么长而且令人沮丧的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
方法对我来说已经足够了。onScroll
覆盖方法包含有用的信息,例如visibleItemCount
及其总计数,最适合确定最后一个可见行。