关于使用X5内核webview如何自定义长按复制弹窗

2020-12-10  本文已影响0人  lllllittlep

总所周知,如果在Android原生提供的webview中,如果我们要实现自定义的长按复制选择弹窗

需要重写Webview的这两个方法

具体的实现思路网上有很多参考文章

今天说一下如果你的项目引用了X5内核的webview,如果想要实现自定义长按复制弹窗会发现,这样实现就无效了

貌似是因为X5内核自己实现了长按点击事件,因为我在使用布局分析工具中发现,当使用X5内核的Webview

显示的自定义弹窗变成了FramLayout布局,如果你使用原生Webview会发现,长安复制弹窗是三个PopupWindow

那接下来的事儿就好办了,我如果拿到X5内核承载复制的FramLayout控件,那么直接替换成我自己的布局不就好了么

那么问题变成如何找到那个FramLayout

在自定义的X5Webview子类中

1。设置长按点击事件

/** * 开启长按文本自定义弹窗 */

public void openCustomLongTextPop(){         

          setOnLongClickListener(new OnLongClickListener() {

                @Override public boolean onLongClick(View v) {                         getViewTreeObserver().addOnGlobalLayoutListener(new                         ViewTreeObserver.OnGlobalLayoutListener() {

                                    @Override public void onGlobalLayout() {                                         getViewTreeObserver().removeOnGlobalLayoutListener(this);                                         foreachView(X5WebView.this);

                                    }

                        });

                        return false;

                }

            });

}

2.遍历找到最上面的FramLayout,就是我们想要找到FramLayout

public void foreachView(View view) {

        if (view instanceof ViewGroup) {

                if(((ViewGroup) view).getChildCount()<=0)return;

                View childAt1 = ((ViewGroup)                 view).getChildAt(((ViewGroup)view).getChildCount()-1);

                if (view instanceof FrameLayout && !(view instanceof X5WebView)) {                                    Log.e("X5Webview", "childCount:" + frameLayout.getChildCount());                     repleaceCopyPopView(frameLayout); return; } foreachView(childAt1);                        }

        foreachView(childAt1);

        }

}

3.替换我们自己的布局

/** * 替换复制弹窗的方法 * @param frameLayout */private void repleaceCopyPopView(FrameLayout frameLayout) {

        View childAt = frameLayout.getChildAt(0);
        frameLayout.removeView(childAt);
        View   customCopyLayout = createCustomCopyLayout();

        frameLayout.postDelayed(new Runnable() {

            @Overridepublic void run() {

                frameLayout.addView(customCopyLayout);

               }

        },500);

}

4.我们项目中的自定义布局,仅供参考

private View createCustomCopyLayout() {

LinearLayout linearLayout = new LinearLayout(this.getContext()); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams((int) Utils.dp2px(200f), (int) Utils.dp2px(40f)); linearLayout.setLayoutParams(layoutParams); linearLayout.setBackgroundResource(R.drawable.shap_corner2_white_stroke1_ededed); LinearLayout.LayoutParams childLayoutParams = new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1);// View actionSelectView = LayoutInflater.from(this.getContext()).inflate(R.layout.layout_longpress_copywindow,null); TextView textView = new TextView(this.getContext()); textView.setText("复制"); textView.setTextColor(Color.BLACK); textView.setGravity(Gravity.CENTER); textView.setLayoutParams(childLayoutParams); TextView textView1 = new TextView(this.getContext()); textView1.setText("笔记"); textView1.setTextColor(Color.BLACK); textView1.setGravity(Gravity.CENTER); textView1.setLayoutParams(childLayoutParams); TextView textView2 = new TextView(this.getContext()); textView2.setText("分享"); textView2.setTextColor(Color.BLACK); textView2.setGravity(Gravity.CENTER); textView2.setLayoutParams(childLayoutParams); linearLayout.addView(textView); linearLayout.addView(textView1); linearLayout.addView(textView2); textView.setOnClickListener(v -> { getSelectedData("复制"); performClickEvent(); }); textView1.setOnClickListener(v -> { performClickEvent(); getSelectedData("笔记"); }); textView2.setOnClickListener(v -> { getSelectedData("分享"); performClickEvent(); }); return linearLayout;

}

5.最后一步,当你点击了自己的按钮后,还要模拟一下点击事件,让弹窗消失

/** * 模拟点击事件,达到复制弹窗消失目的 */

public void performClickEvent() {

        MotionEvent me = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0,         0);// onTouch(mPageWidget, me); dispatchTouchEvent(me);

    }

6.补充两个小细节

当我这么实现后,发现点击html中的视频横屏的时候,发现他在顶部又创建了一个framlayout,那么这时候当我们再点击长按的时候,找第一个就不对了,会在视频framlayout中又创建了一个,所以我要将如果之前找到过的复制弹窗进行下标识,更改查找方法为

/** * 寻找长按复制弹窗,并替换自己的定义的View * * 当视频容器未加入视图时,Webview中只有一个承载复制弹窗的容器, * 如果点击播放了视频,这时候Webview中有两个Framlayout,而且这两个FragmLayout的顺序跟出现顺序有关系 * 一步小心可能把视频播放控件remove掉, * 所以当第一次找到复制弹窗的时候要加一个Tag标记 * 如果找到了标记位,直接替换标记位里的view * @param view */

public static final String CopyFramTag = "myCustomCopyPopTag";

public void foreachView(View view) {

        if (view instanceof ViewGroup) {

            if(((ViewGroup) view).getChildCount()<=0)return;

            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {

                View childAt = ((ViewGroup) view).getChildAt(i);                 if(CopyFramTag.equals(childAt.getTag())){

                    repleaceCopyPopView((FrameLayout) childAt); return;

                }

            }

                View childAt1 = ((ViewGroup) view).getChildAt(((ViewGroup)                 view).getChildCount()-1);

                if (view instanceof FrameLayout && !(view instanceof X5WebView)) {                         view.setTag(CopyFramTag);

                        FrameLayout frameLayout = (FrameLayout) view;

                        Log.e("X5Webview", "childCount:" + frameLayout.getChildCount());

                        repleaceCopyPopView(frameLayout); return;

                }

                foreachView(childAt1);

            }

        }

第二个细节:

    当点击的位置比较考右边这时候,弹窗会有一半显示在屏幕外,这时候需要我们在替换自己布局后,判断下布局的位置,做一个平移操作,补充替换代码为

/** * 替换复制弹窗的方法 * @param frameLayout */

private void repleaceCopyPopView(FrameLayout frameLayout) {

View childAt = frameLayout.getChildAt(0); frameLayout.removeView(childAt); View customCopyLayout = createCustomCopyLayout();

frameLayout.postDelayed(new Runnable() {

            @Override public void run() {

                // frameLayout.setLayoutParams(layoutParams);                 frameLayout.addView(customCopyLayout); //监听布局变化                 frameLayout.addOnLayoutChangeListener(new OnLayoutChangeListener() {                         @Override public void onLayoutChange(View v, int left, int top, int right,                         int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {

                            float x = frameLayout.getX(); float v1 =                             VideoPlayUtils.getScreenWidth(v.getContext()) - Utils.dp2px(200f);

                            //最小距离 //如果弹窗位置,超出了屏幕,将弹窗平移进来, if(x >                                 VideoPlayUtils.getScreenWidth(v.getContext()) - v1){                                                        Log.e("X5Webview","x: " + x + " v1: " + v1 + " tranns: " + (x-v1));                             frameLayout.animate().translationX(v1-x-Utils.dp2px(10)).start();

                        }

                    }

                });

            }

            }, 500);

}

至此应该可以完美实现,自定义弹窗更能,

提示:使用原生方法的js注入同样要写。和原生方案一样

代码不知道怎么粘贴,格式有点乱,见谅。

上一篇 下一篇

猜你喜欢

热点阅读