我想我理解了你的问题。您希望在展开电子邮件时将主题行向上推,而将其他电子邮件向下推。我试图实现在 Gmail 应用程序中显示电子邮件的想法。我认为我非常接近解决方案,因为推动不够顺畅。但是,我想在这里分享答案,以表达我对您问题的看法。
I have created a GitHub repository 从那里你可以看到我的实现。我还在那里添加了一个自述文件来解释整体想法。
我尝试使用具有不同ViewTypes 的RecyclerView 来实现整个事情。我添加了一个如下所示的适配器。
public class RecyclerViewWithHeaderFooterAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int HEADER_VIEW = 1;
private static final int GROUPED_VIEW = 2;
private static final int EXPANDED_VIEW = 3;
private ArrayList<Integer> positionTracker; // Take any list that matches your requirement.
private Context context;
private ZoomListener zoomListener;
// Define a constructor
public RecyclerViewWithHeaderFooterAdapter(Context context, ZoomListener zoomListener) {
this.context = context;
this.zoomListener = zoomListener;
positionTracker = Utilities.populatePositionsWithDummyData();
}
// Define a ViewHolder for Header view
public class HeaderViewHolder extends ViewHolder {
public HeaderViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Do whatever you want on clicking the item
}
});
}
}
// Define a ViewHolder for Expanded view
public class ExpandedViewHolder extends ViewHolder {
public ExpandedViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Do whatever you want on clicking the item
}
});
}
}
// Define a ViewHolder for Expanded view
public class GroupedViewHolder extends ViewHolder {
public GroupedViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Do whatever you want on clicking the item
}
});
}
}
// And now in onCreateViewHolder you have to pass the correct view
// while populating the list item.
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
if (viewType == EXPANDED_VIEW) {
v = LayoutInflater.from(context).inflate(R.layout.list_item_expanded, parent, false);
ExpandedViewHolder vh = new ExpandedViewHolder(v);
return vh;
} else if (viewType == HEADER_VIEW) {
v = LayoutInflater.from(context).inflate(R.layout.list_item_header, parent, false);
HeaderViewHolder vh = new HeaderViewHolder(v);
return vh;
} else {
v = LayoutInflater.from(context).inflate(R.layout.list_item_grouped, parent, false);
GroupedViewHolder vh = new GroupedViewHolder(v);
return vh;
}
}
// Now bind the ViewHolder in onBindViewHolder
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
try {
if (holder instanceof ExpandedViewHolder) {
ExpandedViewHolder vh = (ExpandedViewHolder) holder;
vh.bindExpandedView(position);
} else if (holder instanceof GroupedViewHolder) {
GroupedViewHolder vh = (GroupedViewHolder) holder;
} else if (holder instanceof HeaderViewHolder) {
HeaderViewHolder vh = (HeaderViewHolder) holder;
}
} catch (Exception e) {
e.printStackTrace();
}
}
// Now the critical part. You have return the exact item count of your list
// I've only one footer. So I returned data.size() + 1
// If you've multiple headers and footers, you've to return total count
// like, headers.size() + data.size() + footers.size()
@Override
public int getItemCount() {
return DEMO_LIST_SIZE; // Let us consider we have 6 elements. This can be replaced with email chain size
}
// Now define getItemViewType of your own.
@Override
public int getItemViewType(int position) {
if (positionTracker.get(position).equals(HEADER_VIEW)) {
// This is where we'll add the header.
return HEADER_VIEW;
} else if (positionTracker.get(position).equals(GROUPED_VIEW)) {
// This is where we'll add the header.
return GROUPED_VIEW;
} else if (positionTracker.get(position).equals(EXPANDED_VIEW)) {
// This is where we'll add the header.
return EXPANDED_VIEW;
}
return super.getItemViewType(position);
}
// So you're done with adding a footer and its action on onClick.
// Now set the default ViewHolder for NormalViewHolder
public class ViewHolder extends RecyclerView.ViewHolder {
// Define elements of a row here
public ViewHolder(View itemView) {
super(itemView);
// Find view by ID and initialize here
}
public void bindExpandedView(final int position) {
// bindExpandedView() method to implement actions
final WebView webView = itemView.findViewById(R.id.email_details_web_view);
webView.getSettings().setBuiltInZoomControls(true);
webView.getSettings().setDisplayZoomControls(false);
webView.loadUrl("file:///android_asset/sample.html");
webView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
zoomListener.onZoomListener(position);
}
});
}
}
}
扩展的列表项包含一个WebView,它有一个包装器wrap_content。您将在list_item_expanded.xml 中找到以下布局。
<?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="wrap_content">
<WebView
android:id="@+id/email_details_web_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:scrollbars="none"
tools:ignore="WebViewLayout" />
</RelativeLayout>
我尝试为实验添加一些虚拟数据,因此编写了Utility 类。 RecyclerView 设置为反向布局,因为这是在RecyclerView 中显示对话的普遍期望。
关键思想是scrollToPosition 在扩展WebView 时。这样感觉就像物品被向上和向下推动以适应扩展。希望你能明白。
我在这里添加了一些屏幕截图,让您了解到目前为止我可以实现的目标。
请注意,推送机制不顺畅。我将致力于此。但是,我想我应该把它贴在这里,因为这可能会帮助你思考。我想建议您clone the repository 并运行应用程序以检查整体实现。让我知道是否有任何反馈。