首页 文章 精选 留言 我的

精选列表

搜索[可视化效果],共10007篇文章
优秀的个人博客,低调大师

Android 5中不同效果的Toast

一、运行的结果 二、主要的代码 package com.otn.android.toast; import java.util.Timer; import java.util.TimerTask; import android.app.Activity; import android.app.AlertDialog; import android.os.Bundle; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; public class MyToast extends Activity implements OnClickListener { private static final String TOASTBTN_1 = "这是默认的Toast显示"; private static final String TOASTBTN_2 = "这是自定义位置的Toast显示"; private static final String TOASTBTN_3 = "这是带图片的Toast显示"; private static final String TOASTBTN_4 = "这是完全自定义的Toast显示"; private static final String TOASTBTN_5 = "这是长时间的Toast显示"; private Button toastBtn_1, toastBtn_2, toastBtn_3, toastBtn_4, toastBtn_5; private Toast toast = null; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.main); toastBtn_1 = (Button) findViewById(R.id.button_1); toastBtn_2 = (Button) findViewById(R.id.button_2); toastBtn_3 = (Button) findViewById(R.id.button_3); toastBtn_4 = (Button) findViewById(R.id.button_4); toastBtn_5 = (Button) findViewById(R.id.button_5); toastBtn_1.setOnClickListener(this); toastBtn_2.setOnClickListener(this); toastBtn_3.setOnClickListener(this); toastBtn_4.setOnClickListener(this); toastBtn_5.setOnClickListener(this); } @Override public void onClick(View v) { AlertDialog.Builder builder; AlertDialog dialog; switch (v.getId()) { case R.id.button_1: toast.makeText(getApplicationContext(), TOASTBTN_1, Toast.LENGTH_LONG).show(); break; case R.id.button_2: toast = Toast.makeText(getApplicationContext(), TOASTBTN_2, Toast.LENGTH_LONG); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); break; case R.id.button_3: toast = Toast.makeText(getApplicationContext(), TOASTBTN_3, Toast.LENGTH_LONG); toast.setGravity(Gravity.CENTER, 50, -100); LinearLayout layout = (LinearLayout) toast.getView(); ImageView image = new ImageView(getApplicationContext()); image.setImageResource(R.drawable.wallpaper_tree_small); layout.addView(image, 0); toast.show(); break; case R.id.button_4: LayoutInflater inflater = getLayoutInflater(); View view = inflater.inflate(R.layout.userdefinedtoast, (ViewGroup) findViewById(R.id.toast_layout)); TextView txtView_Title = (TextView) view .findViewById(R.id.txt_Title); TextView txtView_Context = (TextView) view .findViewById(R.id.txt_context); ImageView imageView = (ImageView) view .findViewById(R.id.image_toast); toast = new Toast(getApplicationContext()); toast.setGravity(Gravity.CENTER, 0, 0); toast.setDuration(Toast.LENGTH_LONG); toast.setView(view); toast.show(); break; case R.id.button_5: LayoutInflater inflater1 = getLayoutInflater(); View view1 = inflater1.inflate(R.layout.userdefinedtoast, (ViewGroup) findViewById(R.id.toast_layout)); TextView txtView_Title1 = (TextView) view1 .findViewById(R.id.txt_Title); TextView txtView_Context1 = (TextView) view1 .findViewById(R.id.txt_context); ImageView imageView1 = (ImageView) view1 .findViewById(R.id.image_toast); builder = new AlertDialog.Builder(this); builder.setView(view1); dialog = builder.create(); dialog.show(); toast.makeText(this, TOASTBTN_5, Toast.LENGTH_LONG).show(); break; default: break; } } }

优秀的个人博客,低调大师

效果评测体系:用指标定义“好用”

自动化上线了,到底好不好用,不能凭感觉。我的经验是,必须建一套评测指标:准确率、时效、稳定、覆盖、满意度,定期量。评测做起来,好坏才看得见,优化才不打空。把指标当成尺子,自动化才既快又透明,业务和 IT 才说得上同一门语言。很多团队只报“建了多少个”,从不报“好用不好用”,到复盘才发现一半在凑数,这个教训很常见。把好用这件事量化,自动化才既快又透明。把评测当日常功课,优化才不打空,业务也才服气。

优秀的个人博客,低调大师

Android自定义柱状图表效果

本文通过示例代码介绍如何自定义简单的直方图表,此图表并非常见的直方图表,而是可以分组的。此文不会过多涉及原理,比较简单,示例图片如下(gif图片没有制作好,有闪烁,请见谅): 对于该示例的代码实现,其实重点在于坐标轴、文字、直方图的位置控制,需要随滑动距离而动态更新。注意事项会在示例代码中标注。下面贴出示例代码 public class MultiGroupHistogramView extends View { private int width; private int height; // 坐标轴线宽度 private int coordinateAxisWidth; // 组名称字体大小 private int groupNameTextSize; // 小组之间间距 private int groupInterval; // 组内子直方图间距 private int histogramInterval; private int histogramValueTextSize; // 图表数值小数点位数 private int histogramValueDecimalCount; private int histogramHistogramWidth; private int chartPaddingTop; private int histogramPaddingStart; private int histogramPaddingEnd; // 各组名称到X轴的距离 private int distanceFormGroupNameToAxis; // 直方图上方数值到直方图的距离 private int distanceFromValueToHistogram; // 直方图最大高度 private int maxHistogramHeight; // 轴线画笔 private Paint coordinateAxisPaint; // 组名画笔 private Paint groupNamePaint; private Paint.FontMetrics groupNameFontMetrics; private Paint.FontMetrics histogramValueFontMetrics; // 直方图数值画笔 private Paint histogramValuePaint; // 直方图画笔 private Paint histogramPaint; // 直方图绘制区域 private Rect histogramPaintRect; // 直方图表视图总宽度 private int histogramContentWidth; // 存储组内直方图shader color,例如,每组有3个直方图,该SparseArray就存储3个相对应的shader color private SparseArray<int[]> histogramShaderColorArray; private List<MultiGroupHistogramGroupData> dataList; private SparseArray<Float> childMaxValueArray; private Scroller scroller; private int minimumVelocity; private int maximumVelocity; private VelocityTracker velocityTracker; public MultiGroupHistogramView(Context context) { this(context, null); } public MultiGroupHistogramView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public MultiGroupHistogramView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs); } private void init(AttributeSet attrs) { setLayerType(View.LAYER_TYPE_HARDWARE, null); TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.MultiGroupHistogramView); coordinateAxisWidth = typedArray.getDimensionPixelSize(R.styleable.MultiGroupHistogramView_coordinateAxisWidth, DisplayUtil.dp2px(2)); // 坐标轴线颜色 int coordinateAxisColor = typedArray.getColor(R.styleable.MultiGroupHistogramView_coordinateAxisColor, Color.parseColor("#434343")); // 底部小组名称字体颜色 int groupNameTextColor = typedArray.getColor(R.styleable.MultiGroupHistogramView_groupNameTextColor, Color.parseColor("#CC202332")); groupNameTextSize = typedArray.getDimensionPixelSize(R.styleable.MultiGroupHistogramView_groupNameTextSize, DisplayUtil.dp2px(15)); groupInterval = typedArray.getDimensionPixelSize(R.styleable.MultiGroupHistogramView_groupInterval, DisplayUtil.dp2px(30)); histogramInterval = typedArray.getDimensionPixelSize(R.styleable.MultiGroupHistogramView_histogramInterval, DisplayUtil.dp2px(10)); // 直方图数值文本颜色 int histogramValueTextColor = typedArray.getColor(R.styleable.MultiGroupHistogramView_histogramValueTextColor, Color.parseColor("#CC202332")); histogramValueTextSize = typedArray.getDimensionPixelSize(R.styleable.MultiGroupHistogramView_histogramValueTextSize, DisplayUtil.dp2px(12)); histogramValueDecimalCount = typedArray.getInt(R.styleable.MultiGroupHistogramView_histogramValueDecimalCount, 0); histogramHistogramWidth = typedArray.getDimensionPixelSize(R.styleable.MultiGroupHistogramView_histogramHistogramWidth, DisplayUtil.dp2px(20)); chartPaddingTop = typedArray.getDimensionPixelSize(R.styleable.MultiGroupHistogramView_chartPaddingTop, DisplayUtil.dp2px(10)); histogramPaddingStart = typedArray.getDimensionPixelSize(R.styleable.MultiGroupHistogramView_histogramPaddingStart, DisplayUtil.dp2px(15)); histogramPaddingEnd = typedArray.getDimensionPixelSize(R.styleable.MultiGroupHistogramView_histogramPaddingEnd, DisplayUtil.dp2px(15)); distanceFormGroupNameToAxis = typedArray.getDimensionPixelSize(R.styleable.MultiGroupHistogramView_distanceFormGroupNameToAxis, DisplayUtil.dp2px(15)); distanceFromValueToHistogram = typedArray.getDimensionPixelSize(R.styleable.MultiGroupHistogramView_distanceFromValueToHistogram, DisplayUtil.dp2px(10)); typedArray.recycle(); coordinateAxisPaint = new Paint(Paint.ANTI_ALIAS_FLAG); coordinateAxisPaint.setStyle(Paint.Style.FILL); coordinateAxisPaint.setStrokeWidth(coordinateAxisWidth); coordinateAxisPaint.setColor(coordinateAxisColor); groupNamePaint = new Paint(Paint.ANTI_ALIAS_FLAG); groupNamePaint.setTextSize(groupNameTextSize); groupNamePaint.setColor(groupNameTextColor); groupNameFontMetrics = groupNamePaint.getFontMetrics(); histogramValuePaint = new Paint(Paint.ANTI_ALIAS_FLAG); histogramValuePaint.setTextSize(histogramValueTextSize); histogramValuePaint.setColor(histogramValueTextColor); histogramValueFontMetrics = histogramValuePaint.getFontMetrics(); histogramPaintRect = new Rect(); histogramPaint = new Paint(Paint.ANTI_ALIAS_FLAG); scroller = new Scroller(getContext(), new LinearInterpolator()); ViewConfiguration configuration = ViewConfiguration.get(getContext()); minimumVelocity = configuration.getScaledMinimumFlingVelocity(); maximumVelocity = configuration.getScaledMaximumFlingVelocity(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); width = getMeasuredWidth(); height = getMeasuredHeight(); maxHistogramHeight = height - groupNameTextSize - coordinateAxisWidth - distanceFormGroupNameToAxis - distanceFromValueToHistogram - histogramValueTextSize - chartPaddingTop; } /** * 判断是否可以水平滑动 * @param direction 标识滑动方向 正数:右滑(手指从右至左移动);负数:左滑(手指由左向右移动) * 您可参考ScaollView或HorizontalScrollView理解滑动方向 */ @Override public boolean canScrollHorizontally(int direction) { if (direction > 0) { return histogramContentWidth - getScrollX() - width + histogramPaddingStart + histogramPaddingEnd > 0; } else { return getScrollX() > 0; } } /** * 根据滑动方向获取最大可滑动距离 * @param direction 标识滑动方向 正数:右滑(手指从右至左移动);负数:左滑(手指由左向右移动) * 您可参考ScaollView或HorizontalScrollView理解滑动方向 */ private int getMaxCanScrollX(int direction) { if (direction > 0) { return histogramContentWidth - getScrollX() - width + histogramPaddingStart + histogramPaddingEnd > 0 ? histogramContentWidth - getScrollX() - width + histogramPaddingStart + histogramPaddingEnd : 0; } else if (direction < 0) { return getScrollX(); } return 0; } private float lastX; @Override public boolean onTouchEvent(MotionEvent event) { initVelocityTrackerIfNotExists(); velocityTracker.addMovement(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { if (!scroller.isFinished()) { scroller.abortAnimation(); } lastX = event.getX(); return true; } case MotionEvent.ACTION_MOVE: { int deltaX = (int) (event.getX() - lastX); lastX = event.getX(); // 滑动处理 if (deltaX > 0 &amp;&amp; canScrollHorizontally(-1)) { scrollBy(-Math.min(getMaxCanScrollX(-1), deltaX), 0); } else if (deltaX < 0 &amp;&amp; canScrollHorizontally(1)) { scrollBy(Math.min(getMaxCanScrollX(1), -deltaX), 0); } break; } case MotionEvent.ACTION_UP: { velocityTracker.computeCurrentVelocity(1000, maximumVelocity); int velocityX = (int) velocityTracker.getXVelocity(); fling(velocityX); recycleVelocityTracker(); break; } case MotionEvent.ACTION_CANCEL: { recycleVelocityTracker(); break; } } return super.onTouchEvent(event); } private void initVelocityTrackerIfNotExists() { if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); } } private void recycleVelocityTracker() { if (velocityTracker != null) { velocityTracker.recycle(); velocityTracker = null; } } // ACTION_UP事件触发 private void fling(int velocityX) { if (Math.abs(velocityX) > minimumVelocity) { if (Math.abs(velocityX) > maximumVelocity) { velocityX = maximumVelocity * velocityX / Math.abs(velocityX); } scroller.fling(getScrollX(), getScrollY(), -velocityX, 0, 0, histogramContentWidth + histogramPaddingStart - width, 0, 0); } } @Override public void computeScroll() { if (scroller.computeScrollOffset()) { scrollTo(scroller.getCurrX(), 0); } } public void setDataList(@NonNull List<MultiGroupHistogramGroupData> dataList) { this.dataList = dataList; if (childMaxValueArray == null) { childMaxValueArray = new SparseArray<>(); } else { childMaxValueArray.clear(); } histogramContentWidth = 0; for (MultiGroupHistogramGroupData groupData : dataList) { List<MultiGroupHistogramChildData> childDataList = groupData.getChildDataList(); if (childDataList != null &amp;&amp; childDataList.size() > 0) { for (int i = 0; i < childDataList.size(); i++) { histogramContentWidth += histogramHistogramWidth + histogramInterval; MultiGroupHistogramChildData childData = childDataList.get(i); Float childMaxValue = childMaxValueArray.get(i); if (childMaxValue == null || childMaxValue < childData.getValue()) { childMaxValueArray.put(i, childData.getValue()); } } histogramContentWidth += groupInterval - histogramInterval; } } histogramContentWidth += -groupInterval; postInvalidate(); } /** * 设置组内直方图颜色(并不是设置所有直方图颜色,而是根据每组数据内直方图数量设置) */ public void setHistogramColor(int[]... colors) { if (colors != null &amp;&amp; colors.length > 0) { if (histogramShaderColorArray == null) { histogramShaderColorArray = new SparseArray<>(); } else { histogramShaderColorArray.clear(); } for (int i = 0; i < colors.length; i++) { histogramShaderColorArray.put(i, colors[i]); } } } @Override protected void onDraw(Canvas canvas) { if (width == 0 || height == 0) { return; } int scrollX = getScrollX(); int axisBottom = height - groupNameTextSize - distanceFormGroupNameToAxis - coordinateAxisWidth / 2; canvas.drawLine(coordinateAxisWidth / 2 + scrollX, 0, coordinateAxisWidth / 2 + scrollX, axisBottom, coordinateAxisPaint); canvas.drawLine(scrollX, axisBottom, width + scrollX, axisBottom, coordinateAxisPaint); if (dataList != null &amp;&amp; dataList.size() > 0) { int xAxisOffset = histogramPaddingStart; // 每个直方图在x轴的偏移量 for (MultiGroupHistogramGroupData groupData : dataList) { List<MultiGroupHistogramChildData> childDataList = groupData.getChildDataList(); if (childDataList != null &amp;&amp; childDataList.size() > 0) { int groupWidth = 0; for (int i = 0; i < childDataList.size(); i++) { MultiGroupHistogramChildData childData = childDataList.get(i); histogramPaintRect.left = xAxisOffset; histogramPaintRect.right = histogramPaintRect.left + histogramHistogramWidth; int childHistogramHeight; if (childData.getValue() <= 0 || childMaxValueArray.get(i) <= 0) { childHistogramHeight = 0; } else { childHistogramHeight = (int) (childData.getValue() / childMaxValueArray.get(i) * maxHistogramHeight); } histogramPaintRect.top = height - childHistogramHeight - coordinateAxisWidth - distanceFormGroupNameToAxis - groupNameTextSize; histogramPaintRect.bottom = histogramPaintRect.top + childHistogramHeight; int[] histogramShaderColor = histogramShaderColorArray.get(i); LinearGradient shader = null; if (histogramShaderColor != null &amp;&amp; histogramShaderColor.length > 0) { shader = getHistogramShader(histogramPaintRect.left, chartPaddingTop + distanceFromValueToHistogram + histogramValueTextSize, histogramPaintRect.right, histogramPaintRect.bottom, histogramShaderColor); } histogramPaint.setShader(shader); canvas.drawRect(histogramPaintRect, histogramPaint); String childHistogramHeightValue = StringUtil.NumericScaleByFloor(String.valueOf(childData.getValue()), histogramValueDecimalCount) + childData.getSuffix(); float valueTextX = xAxisOffset + (histogramHistogramWidth - histogramValuePaint.measureText(childHistogramHeightValue)) / 2; // 数值绘制Y轴位置特别处理 float valueTextY = histogramPaintRect.top - distanceFormGroupNameToAxis + (histogramValueFontMetrics.bottom) / 2; canvas.drawText(childHistogramHeightValue, valueTextX, valueTextY, histogramValuePaint); int deltaX = i < childDataList.size() - 1 ? histogramHistogramWidth + histogramInterval : histogramHistogramWidth; groupWidth += deltaX; // 注意此处偏移量累加 xAxisOffset += i == childDataList.size() - 1 ? deltaX + groupInterval : deltaX; } String groupName = groupData.getGroupName(); float groupNameTextWidth = groupNamePaint.measureText(groupName); float groupNameTextX = xAxisOffset - groupWidth - groupInterval + (groupWidth - groupNameTextWidth) / 2; // 组名绘制Y轴位置特别处理 float groupNameTextY = (height - groupNameFontMetrics.bottom / 2); canvas.drawText(groupName, groupNameTextX, groupNameTextY, groupNamePaint); } } } } private LinearGradient getHistogramShader(float x0, float y0, float x1, float y1, int[] colors) { return new LinearGradient(x0, y0, x1, y1, colors, null, Shader.TileMode.CLAMP); } } 代码就这一点,阅读起来应该不难,如有疑问欢迎留言自定义属性如下: <declare-styleable name="MultiGroupHistogramView"> <attr name="coordinateAxisWidth" format="dimension" /> <attr name="coordinateAxisColor" format="color" /> <attr name="groupNameTextColor" format="color" /> <attr name="groupNameTextSize" format="dimension" /> <attr name="groupInterval" format="dimension" /> <attr name="histogramInterval" format="dimension" /> <attr name="histogramValueTextColor" format="color" /> <attr name="histogramValueTextSize" format="dimension" /> <attr name="histogramHistogramWidth" format="dimension" /> <attr name="histogramPaddingStart" format="dimension" /> <attr name="histogramPaddingEnd" format="dimension" /> <attr name="chartPaddingTop" format="dimension" /> <attr name="distanceFormGroupNameToAxis" format="dimension" /> <attr name="distanceFromValueToHistogram" format="dimension" /> <!--图表数值小数点位数--> <attr name="histogramValueDecimalCount"> <enum name="ZERO" value="0" /> <enum name="ONE" value="1" /> <enum name="TWO" value="2" /> </attr> </declare-styleable> 下面贴出使用方法: private void initMultiGroupHistogramView() { Random random = new Random(); int groupSize = random.nextInt(5) + 10; List<MultiGroupHistogramGroupData> groupDataList = new ArrayList<>(); // 生成测试数据 for (int i = 0; i < groupSize; i++) { List<MultiGroupHistogramChildData> childDataList = new ArrayList<>(); MultiGroupHistogramGroupData groupData = new MultiGroupHistogramGroupData(); groupData.setGroupName("第" + (i + 1) + "组"); MultiGroupHistogramChildData childData1 = new MultiGroupHistogramChildData(); childData1.setSuffix("分"); childData1.setValue(random.nextInt(50) + 51); childDataList.add(childData1); MultiGroupHistogramChildData childData2 = new MultiGroupHistogramChildData(); childData2.setSuffix("%"); childData2.setValue(random.nextInt(50) + 51); childDataList.add(childData2); groupData.setChildDataList(childDataList); groupDataList.add(groupData); } multiGroupHistogramView.setDataList(groupDataList); int[] color1 = new int[]{getResources().getColor(R.color.color_orange), getResources().getColor(R.color.colorPrimary)}; int[] color2 = new int[]{getResources().getColor(R.color.color_supper_tip_normal), getResources().getColor(R.color.bg_supper_selected)}; // 设置直方图颜色 multiGroupHistogramView.setHistogramColor(color1, color2); } 完整示例:https://github.com/670832188/TestApp 原文发布时间为:2019-1-3本文作者:乱世白衣本文来自云栖社区合作伙伴“ 安卓巴士Android开发者门户”,了解相关信息可以关注“anzhuobashi”微信公众号

优秀的个人博客,低调大师

Android仿微信文章悬浮窗效果

序言 前些日子跟朋友聊天,朋友Z果粉,前些天更新了微信,说微信出了个好方便的功能啊,我问是啥功能啊,看看我大Android有没有,他说现在阅读公众号文章如果有人给你发微信你可以把这篇文章当作悬浮窗悬浮起来,方便你聊完天不用找继续阅读,听完是不是觉得这叫啥啊,我大Android微信版不是早就有这个功能了吗,我看文章的时候看到过有这个悬浮按钮,但是我一直没有使用过,试了一下还是挺方便的,就想着自己实现一下这个功能,下面看图,大家都习惯了无图言X 原理 看完动图我们来分析一下,如何在每个页面上都存在一个View呢,有些人可能会说,写在base里面,这样每次启动一个新的Activity都要往页面上addView一次,性能不好,再说了,我们作为一个优秀的程序员能干这种重复的事吗,这种方案果断打回去;既然这样的话那我们肯定要在全局加了,那么全局是哪呢?相信了解过Activity源码的朋友肯定知道,全局可以在Window层加啊,这样既能一次性搞定,又不影响性能,说干就干。 实现 1、权限 首先我们要考虑的一个问题就是权限问题,因为要适配Android 7.0 8.0,添加悬浮窗是需要申请权限的,这里参考了Android 悬浮窗权限各机型各系统适配大全这篇文章,适配的比较全,可以直接拿来用。这里需要注意的是,为了适配Android 8.0,Window的类型需要配置一下: 1if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){2//Android8.03mLayoutParams.type=WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;4}else{5//其他版本6mLayoutParams.type=WindowManager.LayoutParams.TYPE_PHONE;7} 2、添加ViewGroup到Window 判断好权限之后,直接添加就可以了 1@SuppressLint("CheckResult") 2privatevoidshowWindow(Contextcontext){ 3mWindowManager=(WindowManager)context.getSystemService(WINDOW_SERVICE); 4mView=LayoutInflater.from(context).inflate(R.layout.article_window,null); 5 6ImageViewivImage=mView.findViewById(R.id.aw_iv_image); 7StringimageUrl=SPUtil.getStringDefault(ARTICLE_IMAGE_URL,""); 8RequestOptionsrequestOptions=RequestOptions.circleCropTransform(); 9requestOptions.placeholder(R.mipmap.ic_launcher_round).error(R.mipmap.ic_launcher_round);10Glide.with(context).load(imageUrl).apply(requestOptions).into(ivImage);1112initListener(context);1314mLayoutParams=newWindowManager.LayoutParams();15if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){16mLayoutParams.type=WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;17}else{18mLayoutParams.type=WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;19}20mLayoutParams.format=PixelFormat.RGBA_8888;//窗口透明21mLayoutParams.gravity=Gravity.LEFT|Gravity.TOP;//窗口位置22mLayoutParams.flags=WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;23mLayoutParams.width=200;24mLayoutParams.height=200;25mLayoutParams.x=mWindowManager.getDefaultDisplay().getWidth()-200;26mLayoutParams.y=0;27mWindowManager.addView(mView,mLayoutParams);28} 3、View的拖拽实现 借助WindowManager.LayoutParams来实现,mLayoutParams.x和mLayoutParams.y分别表示mView左上角的横纵坐标,所以我们只需要改动这两个值就行了,当ACTION_UP时,计算当前mView的中心点相对窗口的位置,然后将mView动态滑动到窗口左边或者右边: 1//设置触摸滑动事件 2mView.setOnTouchListener(newView.OnTouchListener(){ 3intstartX,startY;//起始点 4booleanisMove;//是否在移动 5longstartTime; 6intfinalMoveX;//最后通过动画将mView的X轴坐标移动到finalMoveX 7 8@Override 9publicbooleanonTouch(Viewv,MotionEventevent){10switch(event.getAction()){11caseMotionEvent.ACTION_DOWN:12startX=(int)event.getX();13startY=(int)event.getY();14startTime=System.currentTimeMillis();15isMove=false;16returnfalse;17caseMotionEvent.ACTION_MOVE:18mLayoutParams.x=(int)(event.getRawX()-startX);19mLayoutParams.y=(int)(event.getRawY()-startY);20updateViewLayout();//更新mView的位置21returntrue;22caseMotionEvent.ACTION_UP:23longcurTime=System.currentTimeMillis();24isMove=curTime-startTime>100;2526//判断mView是在Window中的位置,以中间为界27if(mLayoutParams.x+mView.getMeasuredWidth()/2>=mWindowManager.getDefaultDisplay().getWidth()/2){28finalMoveX=mWindowManager.getDefaultDisplay().getWidth()-mView.getMeasuredWidth();29}else{30finalMoveX=0;31}3233//使用动画移动mView34ValueAnimatoranimator=ValueAnimator.ofInt(mLayoutParams.x,finalMoveX).setDuration(Math.abs(mLayoutParams.x-finalMoveX));35animator.addUpdateListener((ValueAnimatoranimation)->{36mLayoutParams.x=(int)animation.getAnimatedValue();37updateViewLayout();38});39animator.start();4041returnisMove;42}43returnfalse;44}45}); 4、注意 为了让Window与Activity脱离,这里我们采用Service来做,通过Service来添加和移除View;在权限申请成功之后我们需要通知Service(其实是Activity,可能会有保存数据等操作)作相应改变(提供一个接口给Service),然后在Service中使用广播来通知Activity;最后一个需要注意的地方就是我们需要判断应用程序是否在前台还是后台来添加或移除Window,这里通过使用ActivityLifecycleCallbacks来监听Activity在前台的数量来判断应用程序是在前台还是后台 1classApplicationLifecycle:Application.ActivityLifecycleCallbacks{ 2 3privatevarstarted:Int=0 4 5overridefunonActivityPaused(activity:Activity?){ 6} 7 8overridefunonActivityResumed(activity:Activity?){ 9}1011overridefunonActivityStarted(activity:Activity?){12started++13if(started==1){14Log.e("TAG","应用在前台了!!!")15}16}1718overridefunonActivityDestroyed(activity:Activity?){19}2021overridefunonActivitySaveInstanceState(activity:Activity?,outState:Bundle?){22}2324overridefunonActivityStopped(activity:Activity?){25started--26if(started==0){27Log.e("TAG","应用在后台了!!!")28}29}3031overridefunonActivityCreated(activity:Activity?,savedInstanceState:Bundle?){32}33} 原文发布时间为:2018-10-10 本文作者:24K纯帅豆 本文来自云栖社区合作伙伴“IT先森养成记”,了解相关信息可以关注“IT先森养成记”。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册