English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Now there are more and more floating window applications on mobile phones. For users, the most common floating window application is the floating small control of security software, such as36For 0 Guardian, when the floating window is opened, it is a ball that can be dragged. When the ball is clicked, a large control window appears, allowing for further operations such as releasing phone memory, etc. Inspired by the video from the慕课网, I imitated and implemented it360 Accelerated ball, added the function of releasing memory by clicking the ball.
Since it is a mobile phone, only screen shots are available: as shown in the figure below after implementation: click the switch button to display the available memory percentage of the phone on the floating ball control; when dragging the ball, the ball becomes an Android icon; release the ball, and the ball adheres to the sides of the screen; click the ball, a large control window appears at the bottom of the phone, click the ball inside to release the phone memory; click other areas of the phone screen, the large window disappears, and the ball reappears.
The effect is as follows:
Next are some important steps to be implemented:
1.Implementation of FloatCircleView (custom view)
The process of implementing FloatCircleView is the process of customizing the view.1Customizing View properties 2Obtaining our customized properties in the View constructor 3Overriding onMesure 4Overriding onDraw. Since we did not customize other properties, many steps were saved.
Initialization of various variables, setting the icon to be displayed when dragging the ball, and calculating various memory values. (Used to display on the ball)
public int width=100; public int heigth=100; private Paint circlePaint;//Drawing a circle private Paint textPaint; //Writing text private float availMemory; //Used memory private float totalMemory; //Total memory private String text; //The percentage of used memory displayed private boolean isDraging=false; //Whether in dragging state. private Bitmap src; private Bitmap scaledBitmap; //Scaled image. /** * Initialize the brush and calculate the available memory, total memory, and the percentage of available memory. */ public void initPatints() { circlePaint = new Paint(); circlePaint.setColor(Color.CYAN); circlePaint.setAntiAlias(true); textPaint = new Paint(); textPaint.setColor(Color.WHITE); textPaint.setTextSize(25); textPaint.setFakeBoldText(true); textPaint.setAntiAlias(true); //Set the image src = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); //Scaled image (set the icon to the same size as the floating ball). scaledBitmap = Bitmap.createScaledBitmap(src, width, height, true); //Calculate used memory, total memory, used memory percentage, availMemory= (float) getAvailMemory(getContext()); totalMemory= (float) getTotalMemory(getContext()); text=(int)((availMemory/totalMemory)*100)+"%"; }
onMeasure(); is to set the fixed width and height, passed through setMeasuredDimension(width, height);
onDraw(); is used to draw the floating ball. Define a boolean variable to judge whether the current state is the dragging ball state. If it is the dragging ball state, draw the android icon at this position; if not, draw the small ball. Drawing a small ball is not difficult, the key is to draw text. Below2Picture can deepen the understanding of drawing text.
1.X coordinate when drawing text (1.textPaint.measureText(text); obtain the width of the character.2.Width of the small ball/2-Character width/2).
2.Y coordinate when drawing text (1.Paint.FontMetrics fontMetrics = textPaint.getFontMetrics(); obtain the font attribute measurement class.2.(fontMetrics.ascent + fontMetrics.descent) / 2 Get the height of the character.3.Height of the small ball/2-Font height/2)
Drawing a picture can make it easier to understand:
/** * Draw a small ball and text. If the small ball is in a dragging state, display the android icon; if not, display the small ball. * @param canvas */ @Override protected void onDraw(Canvas canvas) { if (isDraging){ canvas.drawBitmap(scaledBitmap,0,0,null); } //1.Draw a circle canvas.drawCircle(width) / 2, heigth / 2, width / 2, circlePaint); //2.drawText(text float textwidth = textPaint.measureText(text);//Text width float x = width / 2 - textwidth / 2; Paint.FontMetrics fontMetrics = textPaint.getFontMetrics(); float dy = -(fontMetrics.ascent + fontMetrics.descent) / 2; float y = height / 2 + dy; canvas.drawText(text, x, y, textPaint); } }
Method to obtain the used memory and total memory of the phone:
public long getAvailMemory(Context context) { // Get the current available memory size of android ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo(); am.getMemoryInfo(mi); //mi.availMem; Current available memory of the system //return Formatter.formatFileSize(context, mi.availMem);// Normalize the obtained memory size return mi.availMem/(1024*1024); } public long getTotalMemory(Context context) { String str1 = "/proc/meminfo";// System memory information file String str2; String[] arrayOfString; long initial_memory = 0; try { FileReader localFileReader = new FileReader(str1); BufferedReader localBufferedReader = new BufferedReader( localFileReader, 8192); str2 = localBufferedReader.readLine();// Read the first line of meminfo, the total system memory size arrayOfString = str2.split("\\s+); for (String num : arrayOfString) { Log.i(str2, num + "\t"); } initial_memory = Integer.valueOf(arrayOfString[1].intValue() * 1024;// Get the total system memory, unit is KB, multiplied by1024Convert to Byte localBufferedReader.close(); } } //return Formatter.formatFileSize(context, initial_memory);// Byte to KB or MB, normalize memory size specification return initial_memory/(1024*1024); }
2.Create WindowManager window management class, manage the floating ball and the bottom large window.
The WindowManager class. It is used to manage the display and hide of the entire floating ball and the bottom large window of the phone.
It must be added in the Manifest file with <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> Permission.
Get the WindowManager class through WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Use wm.addView(view, params) to add the view to the window.
Use wm.remove(view,params) to remove the view from the window.
Use wm.updateViewLayout(view,params) to update the view.
WindowManager.LayoutParams is used to set various properties of the view.
1.Create FloatViewManager instance.
//Singleton pattern creation public static FloatViewManager getInstance(Context context){ if (inStance==null){ synchronized(FloatViewManager.class){ if (inStance==null){ new FloatViewManager(context); } } } return inStance; }
2.Methods to display the floating ball and display the bottom window. (The method to display the window is similar to that of displaying the floating ball.)
/** * Display the floating window */ public void showFloatCircleView() { //Parameter settings if (params == null) { params = new WindowManager.LayoutParams(); //Width and height params.width = circleView.width; params.height = circleView.height; //Alignment method params.gravity = Gravity.TOP | Gravity.LEFT; //Offset params.x=0; params.y = 0; //Type params.type = WindowManager.LayoutParams.TYPE_TOAST; //Set the window properties. params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; //Pixel format params.format = PixelFormat.RGBA_8888; } //Add the ball to the window. wm.addView(circleView, params); } public void showFloatCircleView() { ...... }
3.When the program starts, first create a floating ball, which can be dragged. Clicking the ball will display the bottom window (FloatMenuView) at the bottom of the phone, and the ball will be hidden. Therefore, for the ball (circleView), it needs to set setOnTouchListener and setOnClickListener event listeners.
Analyze the event distribution of the ball; For the ball:
When ACTION_DOWN occurs, record the downX, downY of the ball, as well as startX, startY
When ACTION_MOVE occurs, set the drag status of circleView to true, record the moveX and moveY of the ball, calculate the distance moved by the ball (dx, dy), and then update the position of the ball according to wm.updateViewLayout(circleView, params);. Finally, assign the last move coordinates to startX, startY.
When ACTION_UP occurs, set the drag status of circleView to false, record the coordinates at the time of lifting, upx, and according to upx and the screen width of the phone/2to make a judgment, to determine whether the final ball is stuck on the left side or the right side of the screen. The following is the error of the ball dragging. When the ball is dragged less than10pixels, the click event of the ball can be triggered. (The Touch event of the ball has priority over the click event of the ball. When the Touch event returns true, this event is consumed and no longer passed down. When the Touch event returns false, this event continues to pass down, thus triggering the click event of the ball.)
Click event of the ball: Click the ball, hide the floating ball, and display the bottom window of the phone. And set the transition animation when the bottom window appears.
//Set touch listener for circleView. private View.OnTouchListener circleViewOnTouchListener=new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: //The last coordinates at the time of pressing, according to ACTION_MOVE. startX = event.getRawX(); startY = event.getRawY(); //The coordinates at the time of pressing. downX = event.getRawX(); downY = event.getRawY(); break; case MotionEvent.ACTION_MOVE: circleView.setDrageState(true); moveX = event.getRawX(); moveY=event.getRawY(); float dx = moveX -startX; float dy=moveY-startY; params.x+=dx; params.y+=dy; wm.updateViewLayout(circleView,params); startX= moveX; startY=moveY; break; case MotionEvent.ACTION_UP: float upx=event.getRawX(); if (upx>getScreenWidth();/2){ params.x=getScreenWidth();-circleView.width; } params.x=0; } circleView.setDrageState(false); wm.updateViewLayout(circleView,params); if (Math.abs(moveX-downX)>10){ return true; } return false; } default: break; } return false; } }); circleView.setOnTouchListener(circleViewOnTouchListener); circleView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //Toast.makeText(, "onclick", Toast.LENGTH_SHORT).show(); //Hide circleView, show the menu bar. wm.removeView(circleView); showFloatMenuView(); floatMenuView.startAnimation(); } });
3.MyProgreeView (Implementation of the ball in the bottom window of the phone).
1.Initialize the pens, listen to the view's gestures. Listen to single-click and double-click events. (The view must be set as clickable)
private void initPaint() { //Circle drawing pen circlepaint = new Paint(); circlepaint.setColor(Color.argb(0xff, 0x3a, 0x8c, 0x6c)); circlepaint.setAntiAlias(true); //Progress bar drawing pen progerssPaint = new Paint(); progerssPaint.setAntiAlias(true); progerssPaint.setColor(Color.argb(0xff, 0x4e, 0xcc, 0x66)); progerssPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));//Draw overlapping parts //Progress drawing pen textPaint = new Paint(); textPaint.setAntiAlias(true); textPaint.setColor(Color.WHITE); textPaint.setTextSize(25); //Canvas bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); bitmapCanvas = new Canvas(bitmap); //Gesture detection. gestureDetector = new GestureDetector(new MyGertureDetectorListener()); setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return gestureDetector.onTouchEvent(event); } }); //Set the view clickable. setClickable(true); } class MyGertureDetectorListener extends GestureDetector.SimpleOnGestureListener{ @Override public boolean onDoubleTap(MotionEvent e) { ...... //The logic of double-tap event return super.onDoubleTap(e); } @Override public boolean onSingleTapConfirmed(MotionEvent e) { ...... //The logic of single-tap event return super.onSingleTapConfirmed(e); } }
2.Update the status of single-tap and double-tap events with the help of handler. When a single tap occurs, use Bezier curves to achieve a ripple effect. When a double tap occurs, the ripples keep descending, performing memory release, and finally displaying the percentage of used memory after memory release. The handler sends periodic messages to continuously redraw the balls for single-tap and double-tap events. (Redrawing will be discussed in the next section).
//Single-tap event sending period handler. private void startSingleTapAnimation() { handler.postDelayed(singleTapRunnable,200); } private SingleTapRunnable singleTapRunnable=new SingleTapRunnable(); class SingleTapRunnable implements Runnable{ @Override public void run() { count--; if (count>=0) { invalidate();//Keep redrawing. handler.postDelayed(singleTapRunnable,200); } handler.removeCallbacks(singleTapRunnable); count=50; } } } //Double-tap event sending period handler. private void startDoubleTapAnimation() { handler.postDelayed(runnbale,50); } private DoubleTapRunnable runnbale=new DoubleTapRunnable(); class DoubleTapRunnable implements Runnable{ @Override public void run() { num--; if (num>=0){ invalidate();//Keep redrawing. handler.postDelayed(runnbale,50); } handler.removeCallbacks(runnbale); //Release memory. killprocess(); //Calculate the percentage of used memory after release. num=(int)(((float)currentProgress/max)*100); } } }
3. Redraw the click event and double-click event.
Firstly, draw the small ball and the ripple path. //Draw the small ball bitmapCanvas.drawCircle(width / 2, heigth / 2, width / 2, circlepaint); //According to path, draw the ripple path. Reset the last path before each drawing. path.reset(); float y =(1-(float)num/100)*heigth; path.moveTo(width, y); path.lineTo(width, heigth); path.lineTo(0, heigth); path.lineTo(0, y);
Then use Bezier curves to draw the ripple path.
Android-Bezier curves
Application of Bezier curves in Android
There is a detailed explanation of Bezier curves. In fact, it is not necessary to understand it deeply. Just know that it can be used to realize the water ripple effect (Bezier curves have many uses, and the flipping effect can also be realized with it.) Mainly use path.rQuadTo(x1,y1,x2,y2); End point (x2, y2), auxiliary control point (x1, y1) Bezier curve. Therefore, by continuously changing y1position, we can draw the effect of water ripples.
Firstly, judge whether it is a double-click event:
If double-clicked: Set a variable d, and change the value of d continuously (the change of d's value is caused by num, and num is decreasing continuously in the handler. num--;), to draw a Bezier curve. Realize the descending effect of water ripples.
If clicked: Set a count value, and change the count value continuously (the change of count value is implemented in the handler. count--;), first judge whether count can be2Divisible, alternately draw these two Bezier curves (these two Bezier curves are exactly opposite), thus realizing the effect of waves.
(Using a for loop to implement the number of waves, a pair of path.rQuadTo(); can only implement one wave. You can verify it yourself.)
if (!isSingleTap){ float d=(1-(float)num/(100/2))*10; for (int i=0;i<3;i++){ path.rQuadTo(10,-d,20,0); path.rQuadTo(10,d,20,0); } } float d=(float)count/50*10; if (count%2if (count%==0){ for (int i=0;i<=3;i++){ path.rQuadTo(10,-d,30,0); path.rQuadTo(10,d,30,0); } } for (int i=0;i<=3;i++){ path.rQuadTo(10,d,30,0); path.rQuadTo(10,-d,30,0); } } }
The last one is the method to release memory. Remember to add <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/> Permission.
public void killprocess(){ ActivityManager activityManger=(ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE); List<ActivityManager.RunningAppProcessInfo> list=activityManger.getRunningAppProcesses(); if(list!=null) for(int i=0;i<list.size();i++) { ActivityManager.RunningAppProcessInfo apinfo=list.get(i); String[] pkgList=apinfo.pkgList; if(apinfo.importance>ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE) { // Process.killProcess(apinfo.pid); for(int j=0;j<pkgList.length;j++) { boolean flag=pkgList[j].contains("com.example.yyh.animation"360");//Here it needs to be judged whether it is the current application, otherwise it may also end the current application. if(!flag){ activityManger.killBackgroundProcesses(pkgList[j]); } } } }
4.Implementation of FloatMenuView.
1.Create a float_menuview.xml; it includes an ImageView+TextView+Custom MyProgreeView.
The bottom window should be set to be clickable. android:clickable="true";
<?xml version="1.0" encoding="utf"-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#"33000000" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="#F0"2F3942" android:layout_alignParentBottom="true" android:id="@"+id/ll" android:clickable="true" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <ImageView android:layout_width="50dp" android:layout_height="50dp" android:src="@mipmap/ic_launcher" android:layout_gravity="center_vertical" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="15sp" android:textColor="#c"93944" android:text="360 acceleration ball" android:layout_gravity="center_vertical" /> </LinearLayout> <com.example.yyh.animation360.view.MyProgreeView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="10dp" /> </LinearLayout> </RelativeLayout>
2. Add FloatMenuView to the window according to the conditions, using (wm.addView(view, params); to add view to the window.
Use the method wm.remove(view,params); to remove view from the window.) to perform the display and hide of the bottom window view
TranslateAnimation class is used to set the animation effect when the bottom window enters. TranslateAnimation(int fromXType,float fromXValue,int toXType,float toXValue,int fromYType,float fromYValue,int toYType,float toYValue)
int fromXType: The reference values for the starting point in the X-axis direction are3options. (1.Animation.ABSOLUTE: Specific coordinate values, indicating absolute screen pixel units.
2.Animation.RELATIVE_TO_SELF: The coordinate value relative to itself.3.Animation.RELATIVE_TO_PARENT: The coordinate value relative to the parent container.)
float fromXValue: The second parameter is the starting value of the type of the first parameter (for example, if the first parameter is set to Animation.RELATIVE_TO_SELF, the second parameter is 0.1f, means multiplying the coordinate value by 0 for itself.1);
int toXType: The reference values for the end point in the X-axis direction are3The options are the same as the first parameter.
float toValue: The fourth parameter is the starting value of the type of the third parameter.
The parameters in the Y-axis direction are the same. Starting point+End point; (the next parameter after each parameter is the starting value of the previous parameter.)
And set OnTouchListener for this view, the OnTouch event must return false finally, indicating that this event still needs to be passed down. This achieves that when clicking on other areas of the phone, the bottom window is hidden and the floating ball is displayed, there is no change when clicking on the bottom window, and the single-click and double-click events are triggered when clicking on the ball in the bottom window.
View view = View.inflate(getContext(), R.layout.float_menuview, null); LinearLayout linearLayout = (LinearLayout) view.findViewById(R.id.ll); translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF, 0, Animation.RELATIVE_TO_SELF,1.0f, Animation.RELATIVE_TO_SELF, 0); translateAnimation.setDuration(500); translateAnimation.setFillAfter(true); linearLayout.setAnimation(translateAnimation); view.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { FloatViewManager manager = FloatViewManager.getInstance(getContext()); manager.hideFloatMenuView(); manager.showFloatCircleView(); return false; } }); addView(view);
5.MyFloatService
Used to create a single instance of FloatVIewManager, managing the floating ball+Creation and removal of the bottom window of the phone.
public class MyFloatService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { //Used to open FloatViewManager FloatViewManager manager = FloatViewManager.getInstance(this); manager.showFloatCircleView(); super.onCreate(); } }
6.MainActivity implementation
Define an intent to start the service (create a WindowManager singleton object in the service to manage the floating ball and the bottom window of the phone), and close the current activity.
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void startService(View view){ Intent intent=new Intent(this, MyFloatService.class); startService(intent); finish(); } }
That's all for this article. Hope it will be helpful to your study and also hope everyone will support the Naiya Tutorial.
Statement: The content of this article is from the Internet, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, does not undergo manual editing, and does not assume any relevant legal liability. If you find any content suspected of copyright infringement, please send an email to: notice#w3Please replace # with @ when sending an email for reporting. Provide relevant evidence, and once verified, this site will immediately delete the infringing content.