我正在研究一个带中心锁的 HorizontalScrollview。它基于此 stackoverflow 线程中的一些代码:
HorizontalScrollView 与 imageviews 作为一个孩子,而在屏幕中滚动图像的中心应该播放动画?
问题是它没有正确支持方向键导航。它不会滚动到下一个项目,而是跳转位置。我修改了代码,使其正确地与 D-Pad 导航一起使用,但这使得 Touch 滚动不起作用。同样出于某种原因,即使正确添加了 TextView,点击侦听器似乎也被删除了。无论如何,现在的主要问题是,如果我重新添加 onScrollChange 事件的代码,它对 Touch 正常工作,但是如果项目不在屏幕上,则 D-Pad 导航可以跳过一个项目,然后再回到屏幕上。
以下是正在使用的 xml.layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/serenity_bonsai_logo"
android:orientation="vertical"
tools:context=".MainActivity" >
<LinearLayout
android:id="@+id/main_menu_row1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:orientation="horizontal" >
<DigitalClock
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#50000000"
android:textColor="#F0F0F0"
android:textSize="20sp" />
</LinearLayout>
<us.nineworlds.serenity.widgets.CenterLockHorizontalScrollview
android:id="@+id/mainGalleryMenu"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#50000000"
android:layout_centerInParent="true"
android:clickable="true"
android:scrollbars="none" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="150dp"
android:layout_gravity="center_vertical"
android:background="@android:color/transparent"
android:orientation="horizontal"
android:clickable="true" >
</LinearLayout>
</us.nineworlds.serenity.widgets.CenterLockHorizontalScrollview>
</RelativeLayout>
我知道问题在于 onScrollChange 方法以及它如何计算应该是新的中心视图,但不确定如何让 D-Pad 和触摸滚动很好地一起播放。这是CenterLockHorizontalScrollView 类的相关代码。
public class CenterLockHorizontalScrollview extends HorizontalScrollView {
private ListAdapter mAdapter;
private int mCenterViewPosition = -1;
private MenuDataSetObserver menuDataObserver;
private OnItemSelectedListener selectedItemListener;
private boolean keypadScrollEvent = false;
public CenterLockHorizontalScrollview(Context context, AttributeSet attrs) {
super(context, attrs);
this.setHorizontalFadingEdgeEnabled(true);
this.setHorizontalScrollBarEnabled(false);
this.setFadingEdgeLength(5);
this.setSmoothScrollingEnabled(true);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (getChildCount() == 0) {
return;
}
initCenterView();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (getChildCount() == 0)
return;
ViewGroup parent = (ViewGroup) getChildAt(0);
if (parent.getChildCount() == 0)
return;
View FirstChild = parent.getChildAt(0);
int LeftPadding = (getWidth() / 2)
- (FirstChild.getMeasuredWidth() / 2);
View LastChild = parent.getChildAt(getChildCount() - 1);
int RightPadding = (getWidth() / 2)
- (LastChild.getMeasuredWidth() / 2);
if (parent.getPaddingLeft() != LeftPadding
&& parent.getPaddingRight() != RightPadding) {
parent.setPadding(LeftPadding, parent.getPaddingTop(),
RightPadding, parent.getPaddingBottom());
requestLayout();
}
}
/* (non-Javadoc)
* @see android.view.View#onKeyDown(int, android.view.KeyEvent)
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
int totalItems = 0;
if (mAdapter.getCount() > 0) {
totalItems = mAdapter.getCount();
}
int currentPosition = mCenterViewPosition;
if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
if (currentPosition > 0) {
setSelectedIndex(currentPosition - 1);
} else {
setSelectedIndex(totalItems - 1);
}
keypadScrollEvent = true;
scrollToSelectedIndex();
keypadScrollEvent = false;
return true;
}
if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
if (currentPosition < totalItems - 1) {
setSelectedIndex(currentPosition + 1);
} else {
setSelectedIndex(0);
}
keypadScrollEvent = true;
scrollToSelectedIndex();
keypadScrollEvent = false;
return true;
}
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER ||
keyCode == KeyEvent.KEYCODE_ENTER) {
ViewGroup parent = (ViewGroup) getChildAt(0);
View view = parent.getChildAt(mCenterViewPosition);
view.setOnClickListener(new GalleryOnClickListener(view.getContext()));
view.performClick();
return true;
}
return super.onKeyDown(keyCode, event);
}
private int getCenterPositionFromView() {
int scrollingCenterView = getScrollingCenterView();
if (mCenterViewPosition != scrollingCenterView) {
ViewGroup parent = (ViewGroup) getChildAt(0);
View view = parent.getChildAt(scrollingCenterView);
selectedItemListener.onItemSelected(view, scrollingCenterView, scrollingCenterView);
mCenterViewPosition = scrollingCenterView;
}
return scrollingCenterView;
}
private int getScrollingCenterView() {
if(getChildCount() == 0)
return -1;
int centerView= 0;
int centerX = getScrollX() + (getWidth() / 2);
ViewGroup parent = (ViewGroup) getChildAt(0);
if(parent.getChildCount() == 0)
return -1;
View child = parent.getChildAt(0);
while(child != null && child.getRight() <= centerX && centerView < parent.getChildCount())
{
centerView++;
child = parent.getChildAt(centerView);
}
if(centerView >= parent.getChildCount()) {
centerView = parent.getChildCount() - 1;
}
return centerView;
}
public int getCenterViewPosition() {
return mCenterViewPosition;
}
public ListAdapter getAdapter() {
return mAdapter;
}
public void setAdapter(ListAdapter mAdapter) {
this.mAdapter = mAdapter;
if (menuDataObserver != null) {
mAdapter.unregisterDataSetObserver(menuDataObserver);
}
mAdapter.registerDataSetObserver(new MenuDataSetObserver());
}
private void fillViewWithAdapter() {
if (getChildCount() == 0 || mAdapter == null)
return;
ViewGroup parent = (ViewGroup) getChildAt(0);
parent.removeAllViews();
for (int i = 0; i < mAdapter.getCount(); i++) {
parent.addView(mAdapter.getView(i, null, parent));
}
setSelectedIndex(0);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (keypadScrollEvent == false) {
getCenterPositionFromView();
}
initCenterView();
}
private void initCenterView() {
Log.i(getClass().getName(), "initCenterView");
if (getChildCount() == 0)
return;
ViewGroup parent = (ViewGroup) getChildAt(0);
if (parent.getChildCount() == 0)
return;
int centerView = getCenterViewPosition();
if (centerView == -1) {
mCenterViewPosition = 0;
centerView = 0;
}
if (centerView != -1 && centerView != mCenterViewPosition
&& parent.getChildAt(0).getLeft() >= 0) {
scrollToSelectedIndex();
}
if (centerView < 0 || centerView > parent.getChildCount())
return;
for (int i = 0; i <= parent.getChildCount(); i++) {
if (! (parent.getChildAt(i) instanceof TextView)) {
continue;
}
if (i == centerView) {
// Start Animation
//setSelectedIndex(i);
//scrollToSelectedIndex();
return;
} else {
// Remove Animation for other Views
}
}
}
public int getSelectedIndex() {
return getCenterViewPosition();
}
public void setSelectedIndex(int index) {
Log.i(getClass().getName(), "setSelectedIndex");
if (getChildCount() == 0)
return;
ViewGroup parent = (ViewGroup) getChildAt(0);
if (index < 0 || index > parent.getChildCount()) {
throw new ArrayIndexOutOfBoundsException(index);
}
mCenterViewPosition = index;
//onSelectedItemChanged.onSelectedChanged(this, mCenterViewPosition);
selectedItemListener.onItemSelected(parent.getChildAt(index), index, 0);
requestLayout();
}
protected void scrollToSelectedIndex() {
ViewGroup parent = (ViewGroup) getChildAt(0);
View child = parent.getChildAt(mCenterViewPosition);
if (child == null) {
return;
}
int offsetX = ((child.getLeft() + child.getRight()) / 2) - (this.getWidth() / 2);
smoothScrollTo(offsetX, 0);
}
public class MenuDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
fillViewWithAdapter();
}
}
public OnItemSelectedListener getOnItemSelectedListener() {
return selectedItemListener;
}
public void setOnItemSelectedListener(OnItemSelectedListener selectedItemListener) {
this.selectedItemListener = selectedItemListener;
}
}
如果不检查 onScrollChange 中的中心,D-Pad 导航可以正常工作,但触摸滚动不能。