Skip to content

Commit

Permalink
feat(android): support appear events for ListView
Browse files Browse the repository at this point in the history
  • Loading branch information
iPel authored and hippy-actions[bot] committed Dec 12, 2023
1 parent 95ebc78 commit 2726c93
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 146 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,24 @@
package com.tencent.mtt.hippy.views.hippylist;

import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static com.tencent.renderer.node.RenderNode.FLAG_LAZY_LOAD;

import android.view.MotionEvent;
import android.view.View.OnTouchListener;
import android.view.ViewParent;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.HippyItemTypeHelper;
import androidx.recyclerview.widget.ItemLayoutParams;
import androidx.recyclerview.widget.RecyclerView.Adapter;
import androidx.recyclerview.widget.RecyclerView.LayoutParams;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.tencent.renderer.node.ListItemRenderNode;
import com.tencent.renderer.node.PullFooterRenderNode;
import com.tencent.renderer.node.PullHeaderRenderNode;
import com.tencent.mtt.hippy.uimanager.RenderManager;
import com.tencent.renderer.node.RenderNode;
import com.tencent.mtt.hippy.utils.LogUtils;
import com.tencent.mtt.hippy.views.hippylist.recyclerview.helper.skikcy.IStickyItemsProvider;
import com.tencent.mtt.hippy.views.list.IRecycleItemTypeChange;
import com.tencent.mtt.hippy.views.refresh.HippyPullFooterView;
import com.tencent.mtt.hippy.views.refresh.HippyPullHeaderView;
import com.tencent.mtt.hippy.views.hippylist.recyclerview.helper.skikcy.IStickyItemsProvider;
import com.tencent.renderer.NativeRender;
import com.tencent.renderer.NativeRenderException;
import com.tencent.renderer.NativeRendererManager;
import com.tencent.renderer.node.ListItemRenderNode;
import com.tencent.renderer.node.PullFooterRenderNode;
import com.tencent.renderer.node.PullHeaderRenderNode;
import com.tencent.renderer.node.RenderNode;

/**
* Created on 2020/12/22.
Expand Down Expand Up @@ -137,6 +129,12 @@ public void onViewAttachedToWindow(@NonNull HippyRecyclerViewHolder holder) {
}
}

@Override
public void onViewDetachedFromWindow(@NonNull HippyRecyclerViewHolder holder) {
holder.bindNode.onViewHolderDetached();
super.onViewDetachedFromWindow(holder);
}

public void onFooterRefreshCompleted() {
if (footerRefreshHelper != null) {
footerRefreshHelper.onRefreshCompleted();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public class RecyclerViewEventHelper extends OnScrollListener implements OnLayou
private OnPreDrawListener preDrawListener;
private boolean isLastTimeReachEnd;
private int preloadItemNumber;
private Rect reusableExposureStateRect = new Rect();

public RecyclerViewEventHelper(HippyRecyclerView recyclerView) {
this.hippyRecyclerView = recyclerView;
Expand Down Expand Up @@ -328,42 +329,32 @@ public void setExposureEventEnable(boolean enable) {
/**
* 可视面积小于10%,任务view当前已经不在可视区域
*/
private boolean isViewVisible(View view) {
private int calculateExposureState(View view) {
if (view == null) {
return false;
return HippyListItemView.EXPOSURE_STATE_INVISIBLE;
}
Rect rect = new Rect();
boolean visibility = view.getGlobalVisibleRect(rect);
boolean visibility = view.getGlobalVisibleRect(reusableExposureStateRect);
if (!visibility) {
return false;
return HippyListItemView.EXPOSURE_STATE_INVISIBLE;
}
// visible area size of view
float visibleArea = reusableExposureStateRect.height() * reusableExposureStateRect.width();
// total area size of view
float viewArea = view.getMeasuredWidth() * view.getMeasuredHeight();
if (visibleArea >= viewArea) {
return HippyListItemView.EXPOSURE_STATE_FULL_VISIBLE;
} else if (visibleArea > viewArea * 0.1f) {
return HippyListItemView.EXPOSURE_STATE_PART_VISIBLE;
} else {
float visibleArea = rect.height() * rect.width(); //可见区域的面积
float viewArea = view.getMeasuredWidth() * view.getMeasuredHeight();//当前view的总面积
return visibleArea > viewArea * 0.1f;
return HippyListItemView.EXPOSURE_STATE_INVISIBLE;
}
}

protected void checkExposureView(View view) {
if (view instanceof HippyListItemView) {
HippyListItemView itemView = (HippyListItemView) view;
if (isViewVisible(view)) {
if (itemView.getExposureState() != HippyListItemView.EXPOSURE_STATE_APPEAR) {
sendExposureEvent(view, EventUtils.EVENT_LIST_ITEM_APPEAR);
itemView.setExposureState(HippyListItemView.EXPOSURE_STATE_APPEAR);
}
} else {
if (itemView.getExposureState() != HippyListItemView.EXPOSURE_STATE_DISAPPEAR) {
sendExposureEvent(view, EventUtils.EVENT_LIST_ITEM_DISAPPEAR);
itemView.setExposureState(HippyListItemView.EXPOSURE_STATE_DISAPPEAR);
}
}
}
}

protected void sendExposureEvent(View view, String eventName) {
if (eventName.equals(EventUtils.EVENT_LIST_ITEM_APPEAR) || eventName
.equals(EventUtils.EVENT_LIST_ITEM_DISAPPEAR)) {
new HippyViewEvent(eventName).send(view, null);
int newState = calculateExposureState(view);
itemView.moveToExposureState(newState);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.tencent.mtt.hippy.views.list;

import android.content.Context;
Expand All @@ -21,114 +22,139 @@
import android.graphics.Paint;
import android.view.View;
import android.view.ViewGroup;

import com.tencent.mtt.hippy.HippyRootView;
import com.tencent.mtt.hippy.utils.PixelUtil;
import com.tencent.mtt.hippy.views.view.HippyViewGroup;
import com.tencent.renderer.utils.EventUtils;

public class HippyListItemView extends HippyViewGroup {

private static final boolean VIEW_LEVEL_MONITOR_ENABLE = false;
private Paint mPaint;
private static final boolean VIEW_LEVEL_MONITOR_ENABLE = false;
private Paint mPaint;

public final static int EXPOSURE_STATE_WILL_APPEAR = 0;
public final static int EXPOSURE_STATE_APPEAR = 1;
public final static int EXPOSURE_STATE_DISAPPEAR = 2;
public final static int EXPOSURE_STATE_WILL_DISAPPEAR = 3;
public final static int EXPOSURE_STATE_FULL_VISIBLE = 1;
public final static int EXPOSURE_STATE_INVISIBLE = 2;
public final static int EXPOSURE_STATE_PART_VISIBLE = 3;

private int mExposureState = EXPOSURE_STATE_DISAPPEAR;
private int mExposureState = EXPOSURE_STATE_INVISIBLE;

public int getExposureState() {
return mExposureState;
}
@Deprecated
public int getExposureState() {
return mExposureState;
}

public void setExposureState(int state) {
mExposureState = state;
}
@Deprecated
public void setExposureState(int state) {
mExposureState = state;
}

public HippyListItemView(Context context) {
super(context);
public HippyListItemView(Context context) {
super(context);

if (VIEW_LEVEL_MONITOR_ENABLE) {
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setTextSize(PixelUtil.dp2px(16));
mPaint.setTextAlign(Paint.Align.CENTER);
if (VIEW_LEVEL_MONITOR_ENABLE) {
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setTextSize(PixelUtil.dp2px(16));
mPaint.setTextAlign(Paint.Align.CENTER);
}
}
}

@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (VIEW_LEVEL_MONITOR_ENABLE) {
canvas.save();
int selfLevel = calculateSelfLevel();
int hippyLevel = calculateHippyLevel();
int childLevel = calculateChildLevel(this);
canvas.drawText(
"总:" + (selfLevel + childLevel) + " , HP:" + (hippyLevel + childLevel) + " , 子:"
+ childLevel, getWidth() / 2.0f,
getHeight() / 2.0f, mPaint);
canvas.restore();

@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
if (VIEW_LEVEL_MONITOR_ENABLE) {
canvas.save();
int selfLevel = calculateSelfLevel();
int hippyLevel = calculateHippyLevel();
int childLevel = calculateChildLevel(this);
canvas.drawText(
"总:" + (selfLevel + childLevel) + " , HP:" + (hippyLevel + childLevel) + " , 子:"
+ childLevel, getWidth() / 2.0f,
getHeight() / 2.0f, mPaint);
canvas.restore();
}
}

private int calculateSelfLevel() {
int level = 0;
View view = this;
while (true) {
if (view.getParent() != null && view.getParent() instanceof View) {
view = (View) view.getParent();
++level;
} else {
break;
}
}
return level;
}
}

private int calculateSelfLevel() {
int level = 0;
View view = this;
while (true) {
if (view.getParent() != null && view.getParent() instanceof View) {
view = (View) view.getParent();
++level;
} else {
break;
}

private int calculateHippyLevel() {
int level = 0;
View view = this;
while (true) {
if (view.getParent() != null && view.getParent() instanceof View && !(view
.getParent() instanceof HippyRootView)) {
view = (View) view.getParent();
++level;
} else if (view.getParent() instanceof HippyRootView) {
++level;
break;
} else {
break;
}
}
return level;
}
return level;
}

private int calculateHippyLevel() {
int level = 0;
View view = this;
while (true) {
if (view.getParent() != null && view.getParent() instanceof View && !(view
.getParent() instanceof HippyRootView)) {
view = (View) view.getParent();
++level;
} else if (view.getParent() instanceof HippyRootView) {
++level;
break;
} else {
break;
}

private int calculateChildLevel(View view) {
int level = 1;
if (view instanceof ViewGroup) {
int count = this.getChildCount();
if (count != 0) {
int maxLevel = 0;
int currentLevel;
for (int i = 0; i < count; i++) {
currentLevel = calculateChildLevel(((ViewGroup) view).getChildAt(i));
maxLevel = Math.max(maxLevel, currentLevel);
}
level = maxLevel + level;
}
}
return level;
}
return level;
}

private int calculateChildLevel(View view) {
int level = 1;
if (view instanceof ViewGroup) {
int count = this.getChildCount();
if (count != 0) {
int maxLevel = 0;
int currentLevel;
for (int i = 0; i < count; i++) {
currentLevel = calculateChildLevel(((ViewGroup) view).getChildAt(i));
maxLevel = Math.max(maxLevel, currentLevel);

public void moveToExposureState(int state) {
if (state == mExposureState) {
return;
}
switch (state) {
case EXPOSURE_STATE_FULL_VISIBLE:
if (mExposureState == EXPOSURE_STATE_INVISIBLE) {
sendExposureEvent(EventUtils.EVENT_LIST_ITEM_WILL_APPEAR);
}
sendExposureEvent(EventUtils.EVENT_LIST_ITEM_APPEAR);
break;
case EXPOSURE_STATE_PART_VISIBLE:
if (mExposureState == EXPOSURE_STATE_FULL_VISIBLE) {
sendExposureEvent(EventUtils.EVENT_LIST_ITEM_WILL_DISAPPEAR);
} else {
sendExposureEvent(EventUtils.EVENT_LIST_ITEM_WILL_APPEAR);
}
break;
case EXPOSURE_STATE_INVISIBLE:
if (mExposureState == EXPOSURE_STATE_FULL_VISIBLE) {
sendExposureEvent(EventUtils.EVENT_LIST_ITEM_WILL_DISAPPEAR);
}
sendExposureEvent(EventUtils.EVENT_LIST_ITEM_DISAPPEAR);
break;
default:
break;
}
level = maxLevel + level;
}
mExposureState = state;
}

private void sendExposureEvent(String eventName) {
EventUtils.sendComponentEvent(this, eventName, null);
}
return level;
}

// public void setType(int type)
// {
// mType = type;
// }

// public int getType()
// {
// return mType;
// }
}
Loading

0 comments on commit 2726c93

Please sign in to comment.