如何同步容器内动态水平滚动视图的滚动视图位置?
How do I synchronize scrollview positions of dynamic horizontal scroll views inside a container?
我的一个活动中有一个父容器,它调用它的子容器,其中包含一个水平滚动视图作为对象之一。
有点像一个 recyclerview,里面有行对象,其中有一个由水平滚动视图组成的常见 row/item 布局。
我的 objective 是为了同步 horizontalscrollview 的位置,这样,当我在其中一个对象上从位置 1 水平滚动到位置 2 时,所有其他包含 horizontalscrollview 的项目都会从位置更新1 到位置 2。
这是我的主要容器代码:(Activity 代码)
for (int index = 0; index < roomCount; index++) {
Room r2 = ((LobbyReservationRowView) container.getChildAt(index))
.getRoom();
// Log.d("Lobby", "sorting: " + r.getName() + ":" + r.isFree() +
// " -- " + r2.getName() + ":" + r2.isFree());
if (r.equals(r2)) {
Log.d("LobbyActivity", "duplicate room -- " + r.getEmail());
// XXX: minor logic error; same room
// someone else requested also an update, and we got rooms twice
container.removeViewAt(index);
container.addView(v, index);
added = true;
break;
} else if (roomCmp.compare(r, r2) < 0) {
container.addView(v, index);
added = true;
break;
}
}
if (!added) {
container.addView(v);
}
其中 container 是包含以下子布局的布局:(以上代码迭代此布局以生成后续行)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
android:gravity="center_vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:background="#232527"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_height="109dp">
<ImageView
android:id="@+id/roomDefaultIcon"
android:layout_width="116dp"
android:layout_height="82dp"
android:src="@drawable/75"
android:contentDescription="@string/default_room_icon_content_description" />
<LinearLayout
android:id="@+id/titleLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center"
android:layout_toEndOf="@id/roomDefaultIcon"
android:layout_marginStart="16dp"
android:orientation="vertical">
<TextView
android:id="@+id/roomNameLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:layout_marginTop="20dp"
android:textStyle="bold"
android:textSize="14sp"
android:text="@string/tech_room" />
<TextView
android:id="@+id/roomInfoLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/TextInfoColor"
android:visibility="gone"
android:text="(42 persons)" />
</LinearLayout>
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/roomDefaultIcon"
android:id="@+id/horizontal_timebar_view"
android:fillViewport="true">
<com.roombooking.androidview.TimeBarView
android:id="@+id/mainTimeBarView"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:orientation="horizontal"
>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button One"
android:visibility="invisible"/>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button Two"
android:visibility="invisible"/>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button Three"
android:visibility="invisible"/>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button Four"
android:visibility="invisible"/>
</com.roombooking.androidview.TimeBarView>
</HorizontalScrollView>
</RelativeLayout>
</LinearLayout>
<ViewSwitcher
android:id="@+id/modeSwitcher"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:inAnimation="@animator/fadein"
android:outAnimation="@animator/fadeout">
<LinearLayout
android:id="@+id/normalMode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginBottom="10dp"
android:layout_marginEnd="0dp"
android:layout_marginRight="0dp"
android:layout_marginTop="10dp"
android:orientation="horizontal"
android:visibility="visible"
android:weightSum="9" >
<Button
android:id="@+id/bookNowButton"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="3"
android:layout_marginStart="10dp"
android:background="@drawable/button_background"
android:focusable="true"
android:text="@string/book_now"
android:textColor="@android:color/white"
android:layout_marginLeft="10dp" />
<TextView
android:id="@+id/roomStatusLabel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="20dp"
android:layout_marginStart="20dp"
android:layout_weight="5"
android:minWidth="100dp"
tools:text="<status>" />
<Button
android:id="@+id/calendarButton"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical|start"
android:background="@drawable/calendar_small_grey"
android:focusable="true" />
</LinearLayout>
<LinearLayout
android:id="@+id/bookingMode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingBottom="8dp">
<ImageButton
android:id="@+id/cancelButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:background="@drawable/close_button_states"
android:contentDescription="@string/cancel_reservation" />
<com.roombooking.android.view.CustomTimeSpanPicker2
android:id="@+id/timeSpanPicker2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="16dp" />
<AutoCompleteTextView
android:id="@+id/autoCompleteTextView1"
android:layout_width="230dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:completionHint="Your name"
android:completionThreshold="2"
android:hint="@string/hint_your_name"
android:imeOptions="actionDone"
android:inputType="textCapWords|textFilter"
android:lines="1"
android:maxLines="1"
android:textColor="@color/button_color"
android:textColorHint="@color/CalendarWeekTextColor"/>
<TextView
android:layout_gravity="center"
android:id="@+id/hintText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:text="@string/hintText"
android:textColor="@color/CalendarWeekTextColor"/>
<Button
android:id="@+id/reserveButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:background="@drawable/button_background"
android:focusable="true"
android:text="@string/button_reserve"
android:textColor="@android:color/white" />
<TextView
android:id="@+id/newRoomStatusLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:layout_marginLeft="20dp"
android:layout_marginStart="20dp"
android:layout_weight="5"
android:textColor="@android:color/black"
android:minWidth="100dp"
/>
<Button
android:id="@+id/newCalendarButton"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical|end"
android:background="@drawable/calendar_small_grey"
android:focusable="true" />
</LinearLayout>
</ViewSwitcher>
</LinearLayout>
我的重点是包含时间栏的 HorizontalScrollView,它的位置为 1 到 10。例如,如果我滚动到位置 5,接下来的后续行的滚动条位置也应为 5,但我不能同步它们。知道我的代码中可能缺少什么吗?
仅供参考,这里是 LobbyReservationRowView class 代码片段:
public class LobbyReservationRowView extends FrameLayout implements
OnClickListener, OnItemClickListener, HorizontalScrollView.OnScrollChangeListener {
@BindView(R.id.horizontal_timebar_view)
HorizontalScrollView mHorizontalTimeBarView;
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
mHorizontalTimeBarView.scrollTo(mHorizontalTimeBarView.getScrollX(),0);
}
}
很高兴在需要时分享整个示例项目
您可以使用 Android 架构组件中的 LiveData 实现同步滚动。声明一个接口
interface LobbyReservationHSVListener{
void updateScrollPosition(int scrollX);
}
声明一个 MutableLiveData 变量并在您的 activity 中实现 LobbyReservationHSVListener,如下所示:
public class HorizontalActivity extends AppCompatActivity implements
LobbyReservationHSVListener {
MutableLiveData<Integer> hsvPosition = new MutableLiveData<Integer>();
@Override
public void updateScrollPosition(int scrollX) {
hsvPosition.setValue(scrollX);
}
}
在您 activity 的 onCreate 中开始观察您声明的 MutableLiveData。每当它的值发生变化时,循环遍历容器的所有子视图并更新它们的滚动位置。
hsvPosition.observe(this,new Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
for(int i=0; i<container.getChildCount();i++){
HorizontalScrollView hsv = container.getChildAt(i).findViewById(R.id.horizontal_timebar_view);
hsv.smoothScrollTo(integer,0);
}
}
});
在您的 LobbyReservationRowView 中创建一个函数来设置 LobbyReservationHSVListener 对象并在滚动发生变化时调用 updateScrollPosition。
public class LobbyReservationRowView extends FrameLayout implements
OnClickListener, OnItemClickListener, HorizontalScrollView.OnScrollChangeListener {
private LobbyReservationHSVListener hsvUpdateListener;
@BindView(R.id.horizontal_timebar_view)
HorizontalScrollView mHorizontalTimeBarView;
public void setHSVUpdateListener(LobbyReservationHSVListener hsvUpdateListener){
this.hsvUpdateListener = hsvUpdateListener;
}
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
hsvUpdateListener.updateScrollPosition(scrollX);
}
}
不要忘记在将 LobbyReservationRowView
对象添加到容器时调用 setHSVUpdateListener(this)
你应该得到这样的东西:
我的一个活动中有一个父容器,它调用它的子容器,其中包含一个水平滚动视图作为对象之一。 有点像一个 recyclerview,里面有行对象,其中有一个由水平滚动视图组成的常见 row/item 布局。
我的 objective 是为了同步 horizontalscrollview 的位置,这样,当我在其中一个对象上从位置 1 水平滚动到位置 2 时,所有其他包含 horizontalscrollview 的项目都会从位置更新1 到位置 2。
这是我的主要容器代码:(Activity 代码)
for (int index = 0; index < roomCount; index++) {
Room r2 = ((LobbyReservationRowView) container.getChildAt(index))
.getRoom();
// Log.d("Lobby", "sorting: " + r.getName() + ":" + r.isFree() +
// " -- " + r2.getName() + ":" + r2.isFree());
if (r.equals(r2)) {
Log.d("LobbyActivity", "duplicate room -- " + r.getEmail());
// XXX: minor logic error; same room
// someone else requested also an update, and we got rooms twice
container.removeViewAt(index);
container.addView(v, index);
added = true;
break;
} else if (roomCmp.compare(r, r2) < 0) {
container.addView(v, index);
added = true;
break;
}
}
if (!added) {
container.addView(v);
}
其中 container 是包含以下子布局的布局:(以上代码迭代此布局以生成后续行)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical"
android:gravity="center_vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:background="#232527"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_height="109dp">
<ImageView
android:id="@+id/roomDefaultIcon"
android:layout_width="116dp"
android:layout_height="82dp"
android:src="@drawable/75"
android:contentDescription="@string/default_room_icon_content_description" />
<LinearLayout
android:id="@+id/titleLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center"
android:layout_toEndOf="@id/roomDefaultIcon"
android:layout_marginStart="16dp"
android:orientation="vertical">
<TextView
android:id="@+id/roomNameLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:layout_marginTop="20dp"
android:textStyle="bold"
android:textSize="14sp"
android:text="@string/tech_room" />
<TextView
android:id="@+id/roomInfoLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/TextInfoColor"
android:visibility="gone"
android:text="(42 persons)" />
</LinearLayout>
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/roomDefaultIcon"
android:id="@+id/horizontal_timebar_view"
android:fillViewport="true">
<com.roombooking.androidview.TimeBarView
android:id="@+id/mainTimeBarView"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:orientation="horizontal"
>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button One"
android:visibility="invisible"/>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button Two"
android:visibility="invisible"/>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button Three"
android:visibility="invisible"/>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button Four"
android:visibility="invisible"/>
</com.roombooking.androidview.TimeBarView>
</HorizontalScrollView>
</RelativeLayout>
</LinearLayout>
<ViewSwitcher
android:id="@+id/modeSwitcher"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:inAnimation="@animator/fadein"
android:outAnimation="@animator/fadeout">
<LinearLayout
android:id="@+id/normalMode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginBottom="10dp"
android:layout_marginEnd="0dp"
android:layout_marginRight="0dp"
android:layout_marginTop="10dp"
android:orientation="horizontal"
android:visibility="visible"
android:weightSum="9" >
<Button
android:id="@+id/bookNowButton"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="3"
android:layout_marginStart="10dp"
android:background="@drawable/button_background"
android:focusable="true"
android:text="@string/book_now"
android:textColor="@android:color/white"
android:layout_marginLeft="10dp" />
<TextView
android:id="@+id/roomStatusLabel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="20dp"
android:layout_marginStart="20dp"
android:layout_weight="5"
android:minWidth="100dp"
tools:text="<status>" />
<Button
android:id="@+id/calendarButton"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical|start"
android:background="@drawable/calendar_small_grey"
android:focusable="true" />
</LinearLayout>
<LinearLayout
android:id="@+id/bookingMode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingBottom="8dp">
<ImageButton
android:id="@+id/cancelButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|end"
android:layout_marginEnd="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:background="@drawable/close_button_states"
android:contentDescription="@string/cancel_reservation" />
<com.roombooking.android.view.CustomTimeSpanPicker2
android:id="@+id/timeSpanPicker2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="16dp" />
<AutoCompleteTextView
android:id="@+id/autoCompleteTextView1"
android:layout_width="230dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:completionHint="Your name"
android:completionThreshold="2"
android:hint="@string/hint_your_name"
android:imeOptions="actionDone"
android:inputType="textCapWords|textFilter"
android:lines="1"
android:maxLines="1"
android:textColor="@color/button_color"
android:textColorHint="@color/CalendarWeekTextColor"/>
<TextView
android:layout_gravity="center"
android:id="@+id/hintText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:text="@string/hintText"
android:textColor="@color/CalendarWeekTextColor"/>
<Button
android:id="@+id/reserveButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:background="@drawable/button_background"
android:focusable="true"
android:text="@string/button_reserve"
android:textColor="@android:color/white" />
<TextView
android:id="@+id/newRoomStatusLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:layout_marginLeft="20dp"
android:layout_marginStart="20dp"
android:layout_weight="5"
android:textColor="@android:color/black"
android:minWidth="100dp"
/>
<Button
android:id="@+id/newCalendarButton"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical|end"
android:background="@drawable/calendar_small_grey"
android:focusable="true" />
</LinearLayout>
</ViewSwitcher>
</LinearLayout>
我的重点是包含时间栏的 HorizontalScrollView,它的位置为 1 到 10。例如,如果我滚动到位置 5,接下来的后续行的滚动条位置也应为 5,但我不能同步它们。知道我的代码中可能缺少什么吗? 仅供参考,这里是 LobbyReservationRowView class 代码片段:
public class LobbyReservationRowView extends FrameLayout implements
OnClickListener, OnItemClickListener, HorizontalScrollView.OnScrollChangeListener {
@BindView(R.id.horizontal_timebar_view)
HorizontalScrollView mHorizontalTimeBarView;
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
mHorizontalTimeBarView.scrollTo(mHorizontalTimeBarView.getScrollX(),0);
}
}
很高兴在需要时分享整个示例项目
您可以使用 Android 架构组件中的 LiveData 实现同步滚动。声明一个接口
interface LobbyReservationHSVListener{
void updateScrollPosition(int scrollX);
}
声明一个 MutableLiveData 变量并在您的 activity 中实现 LobbyReservationHSVListener,如下所示:
public class HorizontalActivity extends AppCompatActivity implements
LobbyReservationHSVListener {
MutableLiveData<Integer> hsvPosition = new MutableLiveData<Integer>();
@Override
public void updateScrollPosition(int scrollX) {
hsvPosition.setValue(scrollX);
}
}
在您 activity 的 onCreate 中开始观察您声明的 MutableLiveData。每当它的值发生变化时,循环遍历容器的所有子视图并更新它们的滚动位置。
hsvPosition.observe(this,new Observer<Integer>() {
@Override
public void onChanged(Integer integer) {
for(int i=0; i<container.getChildCount();i++){
HorizontalScrollView hsv = container.getChildAt(i).findViewById(R.id.horizontal_timebar_view);
hsv.smoothScrollTo(integer,0);
}
}
});
在您的 LobbyReservationRowView 中创建一个函数来设置 LobbyReservationHSVListener 对象并在滚动发生变化时调用 updateScrollPosition。
public class LobbyReservationRowView extends FrameLayout implements
OnClickListener, OnItemClickListener, HorizontalScrollView.OnScrollChangeListener {
private LobbyReservationHSVListener hsvUpdateListener;
@BindView(R.id.horizontal_timebar_view)
HorizontalScrollView mHorizontalTimeBarView;
public void setHSVUpdateListener(LobbyReservationHSVListener hsvUpdateListener){
this.hsvUpdateListener = hsvUpdateListener;
}
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
hsvUpdateListener.updateScrollPosition(scrollX);
}
}
不要忘记在将 LobbyReservationRowView
对象添加到容器时调用 setHSVUpdateListener(this)
你应该得到这样的东西: