In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article will explain in detail how to achieve multi-process pop-up window effect in Android development. The editor thinks it is very practical, so I share it with you as a reference. I hope you can get something after reading this article.
Background
Sometimes in the pop-up window drawing, it is necessary to pop-up window in the new process, in order to ensure that the pop-up window drawing process will not occupy too much memory and cause the main process to be shut down.
Code implementation
Child process pop-up window
First of all, we need a transparent activity to display as a pop-up window, and the transparent activity exists in the child process, all of which can be implemented in the listing file:
The topics used are defined in res/values/themes.xml:
@ android:color/transparent true false @ android:style/Animation.Translucent
Then set the location and size of the activity:
Public class ProcessActivity extends Activity {... @ SuppressLint ("ClickableViewAccessibility") @ Override protected void onCreate (@ Nullable Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_process); WindowManager.LayoutParams lp = getWindow (). GetAttributes (); lp.width = 950; lp.height = 1700; lp.gravity = Gravity.START; getWindow (). SetAttributes (lp);.}.}
The layout file activity_process.xml used is as follows:
The background color is cyan, two button, one is responsible for displaying the toast, and the other is responsible for ending the pop-up window, we add click event listening to them in onCreate ():
Button button_process = findViewById (R.id.btn_process); Button button_finish = findViewById (R.id.btn_finish); button_process.setOnClickListener (v-> {Toast.makeText (this, "onCreate: Button in sub process has been clicked.", Toast.LENGTH_SHORT). Show (); button_finish.setOnClickListener (v-> {ProcessActivity.this.finish ();})
The next thing to implement is event transmission: because the child process window is a pop-up window, when the clickable component in the pop-up window is not touched, the following activity should undertake the touch event. The implementation of this logic is as follows:
Public class ProcessActivity extends Activity {private View mRootView; @ SuppressLint ("ClickableViewAccessibility") @ Override protected void onCreate (@ Nullable Bundle savedInstanceState) {mRootView = LayoutInflater.from (this) .propagate (R.layout.activity_process, null); setContentView (mRootView); Button button_process = findViewById (R.id.btn_process); Button button_finish = findViewById (R.id.btn_finish);.} @ Override public boolean dispatchTouchEvent (MotionEvent event) {if (event.getAction () = = MotionEvent.ACTION_DOWN) {View target = Utils.getViewTouchedByEvent (mRootView, event); if (target! = null) {target.dispatchTouchEvent (event) Return true;} Intent intent = new Intent (); intent.setAction ("TouchEvent"); intent.putExtra ("event", event); sendBroadcast (intent); return super.dispatchTouchEvent (event);}}
Because the pop-up window and the main window are in two processes, the transmission of touch events needs to be IPC, which is broadcast. Utils.isDebugWindowValidTouched () is responsible for determining whether the current click event has been clicked to a clickable control. The method code is as follows:
Public static View getViewTouchedByEvent (View view, MotionEvent event) {if (view = = null | | event = = null) {return null;} if (! (view instanceof ViewGroup)) {return isDebugWindowValidTouched (view, event)? View: null;} ViewGroup parent = ((ViewGroup) view); int childrenCount = parent.getChildCount (); for (int I = 0; I
< childrenCount; i++) { View target = getViewTouchedByEvent(parent.getChildAt(i), event); if (target != null) { return target; } } return null;} private static boolean isDebugWindowValidTouched(View view, MotionEvent event) { if (event == null || view == null) { return false; } if (view.getVisibility() != View.VISIBLE) { return false; } final float eventRawX = event.getRawX(); // 获取event在屏幕上的坐标 final float eventRawY = event.getRawY(); RectF rect = new RectF(); int[] location = new int[2]; view.getLocationOnScreen(location); // 获取view在屏幕上的坐标位置 float x = location[0]; float y = location[1]; rect.left = x; rect.right = x + view.getWidth(); rect.top = y; rect.bottom = y + view.getHeight(); return rect.contains(eventRawX, eventRawY);} 子进程弹窗窗口ProcessActivity的完整代码如下所示: package com.example.testrxjava; import android.annotation.SuppressLint;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.os.Process;import android.util.Log;import android.view.Gravity;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.WindowManager;import android.widget.Button;import android.widget.CompoundButton;import android.widget.Switch;import android.widget.TextView;import android.widget.Toast;import android.widget.ToggleButton; import androidx.annotation.Nullable; import java.util.ArrayList;import java.util.List; public class ProcessActivity extends Activity { public static final String TAG = "ProcessActivity"; private View mRootView; @SuppressLint("ClickableViewAccessibility") @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mRootView = LayoutInflater.from(this).inflate(R.layout.activity_process, null); setContentView(mRootView); Log.i(TAG, "onCreate: pid = " + Process.myPid()); Button button_process = findViewById(R.id.btn_process); TextView button_finish = findViewById(R.id.btn_finish); button_process.setOnClickListener(v ->{Toast.makeText (this, "onCreate: Button in sub process has been clicked.", Toast.LENGTH_SHORT). Show ();}); button_finish.setOnClickListener (v-> {ProcessActivity.this.finish ();}); ToggleButton toggleButton = findViewById (R.id.toggle) ToggleButton.setOnCheckedChangeListener ((buttonView, isChecked)-> Toast.makeText (ProcessActivity.this, "Toggle button in sub process has been clicked, current state of checking is:" + isChecked, Toast.LENGTH_SHORT) .show (); Switch switch_button = findViewById (R.id.switch_sub_process) Switch_button.setOnCheckedChangeListener ((buttonView, isChecked)-> Toast.makeText (ProcessActivity.this, "Switch in sub process has been clicked, current state of checking is:" + isChecked, Toast.LENGTH_SHORT). Show (); WindowManager.LayoutParams lp = getWindow (). GetAttributes (); lp.width = 950; lp.height = 1700; lp.gravity = Gravity.START GetWindow () .setAttributes (lp);} @ Override public boolean dispatchTouchEvent (MotionEvent event) {if (event.getAction () = = MotionEvent.ACTION_DOWN) {View target = Utils.getViewTouchedByEvent (mRootView, event); if (target! = null) {target.dispatchTouchEvent (event); return true }} Intent intent = new Intent (); intent.setAction ("TouchEvent"); intent.putExtra ("event", event); sendBroadcast (intent); return super.dispatchTouchEvent (event);}}
Main interface
To return to the main interface, you first need to receive the TouchEvent broadcast:
Public class MainActivity extends AppCompatActivity {... Private BroadcastReceiver mReceiver; @ Override protected void onCreate (Bundle savedInstanceState) {... MReceiver = new BroadcastReceiver () {@ Override public void onReceive (Context context, Intent intent) {if (intent.getAction () .equals ("TouchEvent")) {MotionEvent event = intent.getParcelableExtra ("event"); try {Class popupClass = Class.forName ("android.widget.PopupWindow") Field decorViewField = popupClass.getDeclaredField ("mDecorView"); decorViewField.setAccessible (true); Object decorView = decorViewField.get (window); Method dispatchTouchEvent = decorView.getClass (). GetDeclaredMethod ("dispatchTouchEvent", MotionEvent.class); dispatchTouchEvent.invoke (decorView, event) } catch (Exception e) {e.printStackTrace ();}; IntentFilter filter = new IntentFilter ("TouchEvent"); registerReceiver (mReceiver, filter);} @ Override protected void onDestroy () {super.onDestroy (); unregisterReceiver (mReceiver) }}
Because there is also a pop-up window in the main interface, when the touch event is passed from the child process, it needs to be handled by the main process's pop-up window, so the touch event is passed by reflecting the dispatchTouchEvent () method of mDecorView that executes the main process pop-up window in the onReceive () method. The complete code of MainActivity is as follows:
Package com.example.testrxjava; import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.graphics.RectF;import android.os.Bundle;import android.os.Parcelable;import android.util.Log;import android.view.Gravity;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.Button;import android.widget.ListView;import android.widget.PopupWindow;import android.widget.TextView Import androidx.appcompat.app.AppCompatActivity; import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List; public class MainActivity extends AppCompatActivity {private Button mButton; private Button mHide; private BroadcastReceiver mReceiver; @ Override protected void onCreate (Bundle savedInstanceState) {super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); TextView textView = findViewById (R.id.text_view) ListView listView = findViewById (R.id.list); ArrayList list = new ArrayList (); for (int I = 0; I
< 200; i++) { list.add("No." + i); } MyAdapter adapter = new MyAdapter(list, this); listView.setAdapter(adapter); adapter.notifyDataSetChanged(); PopupWindow window = new PopupWindow(this); View windowView = LayoutInflater.from(this).inflate(R.layout.window_layout, null); mButton = windowView.findViewById(R.id.btn_window); mButton.setOnClickListener(view ->{startActivity (new Intent (MainActivity.this, ProcessActivity.class));}); mHide = windowView.findViewById (R.id.btn_hide); mHide.setOnClickListener (v-> {mButton.setVisibility (mButton.getVisibility ()) = = View.VISIBLE? View.GONE: View.VISIBLE);}); window.setTouchInterceptor ((view, motionEvent)-> {if (motionEvent.getAction () = = MotionEvent.ACTION_DOWN) {View target = Utils.getViewTouchedByEvent (windowView, motionEvent); if (target! = null) {target.dispatchTouchEvent (motionEvent); return true }} MainActivity.this.dispatchTouchEvent (motionEvent); return false;}); View rootView = getWindow (). GetDecorView (); window.setOutsideTouchable (false); window.setOnDismissListener (()-> textView.post (()-> {window.showAtLocation (rootView, Gravity.BOTTOM, 0,0);}) Window.setContentView (windowView); window.setWidth (ViewGroup.LayoutParams.MATCH_PARENT); window.setHeight (ViewGroup.LayoutParams.WRAP_CONTENT); findViewById (R.id.root) .setOnClickListener (v-> {Log.i ("MainActivity", "Touch event gets to text view!");}); textView.post (()-> {window.showAtLocation (rootView, Gravity.BOTTOM, 0,0) }); mReceiver = new BroadcastReceiver () {@ Override public void onReceive (Context context, Intent intent) {if (intent.getAction () .equals ("TouchEvent")) {MotionEvent event = intent.getParcelableExtra ("event"); try {Class popupClass = Class.forName ("android.widget.PopupWindow") Field decorViewField = popupClass.getDeclaredField ("mDecorView"); decorViewField.setAccessible (true); Object decorView = decorViewField.get (window); Method dispatchTouchEvent = decorView.getClass (). GetDeclaredMethod ("dispatchTouchEvent", MotionEvent.class); dispatchTouchEvent.invoke (decorView, event) } catch (Exception e) {e.printStackTrace ();}; IntentFilter filter = new IntentFilter ("TouchEvent"); registerReceiver (mReceiver, filter);} @ Override protected void onDestroy () {super.onDestroy (); unregisterReceiver (mReceiver) }} effect
The purple background is the pop-up window of the main process, and the cyan one is the pop-up window of the child process. As you can see from the video, when the event is pressed to the upper component, the upper component will respond; if you press the space in the upper pop-up window, the touch event will be passed down.
This is the end of this article on "how to achieve multi-process pop-up window effect in Android development". I hope the above content can be helpful to you, so that you can learn more knowledge. if you think the article is good, please share it out for more people to see.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.