对网站建设的调研报告,用户界面设计报告,上海做网站比较有名的公司有哪些,网站建设开发实训的目的Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC
#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧#xff0c;以及各种资源分…Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC
关于作者 专注于Android/Unity和各种游戏开发技巧以及各种资源分享网站、工具、素材、源码、游戏等 有什么需要欢迎底部卡片私我交流让学习不再孤单。 实践过程
超出父布局显示
我们实现一个 LinearLayout 布局宽高是200里面嵌套一个 Button 默认是展示出来的。
RelativeLayoutandroid:layout_width200mmandroid:layout_height200mmandroid:backgroundcolor/crane_swl_color_3Buttonandroid:idid/idBtnTextandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:textExcelandroid:textSize26mm /
/RelativeLayout但是我们将 Button 的间距设置超出父布局。默认是不会展示出来的。
RelativeLayoutandroid:layout_width200mmandroid:layout_height200mmandroid:backgroundcolor/crane_swl_color_3Buttonandroid:idid/idBtnTextandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:textExcelandroid:textSize26mm /
/RelativeLayout我们需要借住属性 android:clipChildrenfalse android:clipToPaddingfalse 官方对于第一行的解释 Defines whether a child is limited to draw inside of its bounds or not. 翻译定义一个子视图是否局限于它的范围内。 所以我们设置为false让子视图不局限与自己
官方对于第二行的解释 Defines whether the ViewGroup will clip its drawing surface so as to exclude the padding area. 翻译定义ViewGroup是否将剪辑其绘图表面以排除填充区域。
要特别注意
如果你某个子 View 嵌套了多层然后超出了父布局需要所有的父布局都携带 clipChildren 属性。这个子 View 的最近父布局需要是 RelativeLayout 博主摸了摸秀发并没有去深究为什么其他 ViewGroup 为什么不行。 如下
?xml version1.0 encodingutf-8?
LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:apphttp://schemas.android.com/apk/res-autoxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:clipChildrenfalseandroid:clipToPaddingfalseandroid:orientationverticaltools:context.MainActivitytools:ignoreHardcodedText,InOrMmUsageRelativeLayoutandroid:layout_width200mmandroid:layout_height200mmandroid:backgroundcolor/crane_swl_color_3android:clipChildrenfalseandroid:clipToPaddingfalseButtonandroid:idid/idBtnTextandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_marginStart300mmandroid:textExcelandroid:textSize26mm //RelativeLayout
/LinearLayout溢出的按钮可以点击
有两种方案
方案一
方案一是在整个Activity窗口捕捉点击事件。
Override
public boolean onTouchEvent(MotionEvent event) {//首先定义一个数组用来接收按钮的坐标xy值int[] xy new int[2];//获取按钮的top/left xy值//button变量我在onCreat()函数中已经获取了控件具体按实际情况写button.getLocationOnScreen(xy);//再定义一个数组用来计算控件的bottom/right xy值int[] xy_end new int[2];xy_end[0] buttom.getWidth() xy[0];xy_end[1] buttom.getHeight() xy[1];//现在我们已经得到了按钮的左上坐标和右下坐标//两个点可以确定一个矩形嘛 event里包含了点击的信息//我们判断点击的坐标是否在按钮坐标内实际就是判断点击的xy值是否在上述矩形中if (event.getX() xy[0] event.getX() xy_end[0] event.getY() xy[1] event.getY() xy_end[1]) {//如果是那么就执行里边的代码在这里我们可以callOnClick()按钮//实际体验了一番发现轻点一下和长按均可以激活按钮//但是我的按钮拥有animate()事件所以连续点击会在动画未完成时再次点击按钮//所以我做了个判断让动画未完成时不再执行点击机制如我//实际中读者完全不用这两行代码//让我看看有哪些读者看都不看直接复制代码--手动滑稽//虽说站在巨人肩膀上但是也要搞懂其原理才不会摔下来。if (isMoreShow false xy[0] button.getHeight())return false;//我们callOnClick了按钮也就是模拟点击了按钮button.callOnClick();return false;}return super.onTouchEvent(event);
}不足之处也很明显如果页面点击事件要素过多写入的判断就很多了毕竟你是整个 Activity 自己处理事件了。
推荐方案二委托
小应用场景有时候一个按钮效果很小就很难触发点击事件我们通常会增大下这个点击区间范围。 大应用场景我实现了多个脑图的功能里面因为方便画线穿插过某个UI就用到了此类知识。 其他情况多种多样相信看这篇文章的你也是因为有这个需求才查找的。
小应用场景的实现很简单
直接增大 View 的宽高然后给View设置内边距 padding 或者直接嵌套一层给这个父设置点击但这会增加布局嵌套进而消耗性能。利用委托功能直接增大点击的区间范围。 /*** 扩展点击区域的范围* param view 需要扩展的元素此元素必需要有父级元素* param expendSize 需要扩展的尺寸当然也可以分别设置增大范围*/public static void expendTouchArea(final View view, final int expendSize) {if (view ! null) {final View parentView (View) view.getParent();parentView.post(new Runnable() {Overridepublic void run() {Rect rect new Rect();view.getHitRect(rect); rect.left - expendSize;rect.top - expendSize;rect.right expendSize;rect.bottom expendSize;parentView.setTouchDelegate(new TouchDelegate(rect, view));}});}}
事实是委托就是系统给我们提供的扩大控件点击区域判断范围的代理方式我们看下View类的源码。
class View{/*** The delegate to handle touch events that are physically in this view* but should be handled by another view.*/private TouchDelegate mTouchDelegate null;public boolean onTouchEvent(MotionEvent event) {//...if (mTouchDelegate ! null) {if (mTouchDelegate.onTouchEvent(event)) {return true;}}}/*** Sets the TouchDelegate for this View.*/public void setTouchDelegate(TouchDelegate delegate) {mTouchDelegate delegate;}
}
从源码中可以看到如果设置了TouchDelegatetouchEvent会优先交给TouchDelegate来处理。
package android.view;
import android.graphics.Rect;
/*** Helper class to handle situations where you want a view to have a larger touch area than its* actual view bounds. The view whose touch area is changed is called the delegate view. This* class should be used by an ancestor of the delegate. To use a TouchDelegate, first create an* instance that specifies the bounds that should be mapped to the delegate and the delegate* view itself.* The ancestor should then forward all of its touch events received in its* {link android.view.View#onTouchEvent(MotionEvent)} to {link #onTouchEvent(MotionEvent)}.*/
public class TouchDelegate {private View mDelegateView;private Rect mBounds;private boolean mDelegateTargeted;public TouchDelegate(Rect bounds, View delegateView) {mBounds bounds;mDelegateView delegateView;}public boolean onTouchEvent(MotionEvent event) {int x (int) event.getX();int y (int) event.getY();boolean sendToDelegate false;boolean hit true;boolean handled false;switch (event.getActionMasked()) {case MotionEvent.ACTION_DOWN:mDelegateTargeted mBounds.contains(x, y);sendToDelegate mDelegateTargeted;break;//...}if (sendToDelegate) {final View delegateView mDelegateView;if (hit) {// Offset event coordinates to be inside the target viewevent.setLocation(delegateView.getWidth() / 2, delegateView.getHeight() / 2);} else {// Offset event coordinates to be outside the target view (in case it does// something like tracking pressed state)int slop mSlop;event.setLocation(-(slop * 2), -(slop * 2));}handled delegateView.dispatchTouchEvent(event);}return handled;}
}从源码中 可以看到创建TouchDelegate 需要传入一个Rect(left,top,right,bottom) 和delegateView, onTouchEvent触发时会通过这个Rect来判断点击事件是否落在区域内如果是 则转发给代理view来处理该事件。
复杂场景实现-重点
子 View 超出父布局显示然后触发点击事件同样利用的委托功能但是因为要处理 Touch 需要自定义一下。
?xml version1.0 encodingutf-8?
LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:apphttp://schemas.android.com/apk/res-autoxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:clipChildrenfalseandroid:clipToPaddingfalseandroid:idid/rootLayandroid:orientationverticaltools:context.MainActivitytools:ignoreHardcodedText,InOrMmUsagecn.akitaka.test.TestOverClickandroid:idid/testLayandroid:layout_width200mmandroid:layout_height200mmandroid:backgroundcolor/crane_swl_color_3android:clipChildrenfalseandroid:clickabletrueandroid:clipToPaddingfalse
!--特别留意因为是自定义的RelativeLayoutTouch时间默认只有个down需要设置可点击才能回调所有的事件--Buttonandroid:idid/idBtnTestandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:layout_marginStart300mmandroid:textExcelandroid:textSize26mm //cn.akitaka.test.TestOverClick
/LinearLayout/*** author akitaka 2023/11/22 960576866qq.com* describe TestOverClick*/
public class TestOverClick extends RelativeLayout {public TestOverClick(Context context) {super(context);}public TestOverClick(Context context, AttributeSet attrs) {super(context, attrs);}public TestOverClick(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}public TestOverClick(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);}private void initClickRect() {View rootParent ((View) getParent());// 获取父视图rootParent.post(() - {// 将当前代码放在消息队列中异步执行Rect rect new Rect();// 创建一个矩形对象// 获取当前视图的点击区域 如果太早执行本函数会获取rect失败因为此时UI界面尚未开始绘制无法获得正确的坐标getHitRect(rect);rect.left - 0;rect.top - 0;//布局中控件是距离左300像素 控件本身是200 他俩的中间间距为100 加上按钮的本身宽度rect.right AutoSizeUtils.mm2px(getContext(), 100) btn.getWidth();rect.bottom 0;rootParent.setTouchDelegate(new TouchDelegate(rect, this)); // 设置根视图的触摸委托为当前视图});}private Button btn;//外部的按钮对象设置public void setBtn(Button btn) {this.btn btn;initClickRect();}Overridepublic boolean onTouchEvent(MotionEvent event) {Log.e(TAG, 事件类型: event.getAction());int x (int) event.getX();int y (int) event.getY();
// if () { TODO 重点注意
// //这个if判断是你点击的x、y坐标是否在按钮的范围内不在的话直接进行return不处理即可
// //具体的区间判断范围就需要自己的项目具体调整了。
// return true;
// }switch (event.getAction()) {case MotionEvent.ACTION_DOWN:Log.e(TAG, 按下事件: btn);btn.setBackgroundResource(R.color.purple_200);break;case MotionEvent.ACTION_UP:btn.performClick();Log.e(TAG, 抬起事件: btn);HandlerUtils.INSTANCE.postRunnable(() - {btn.setBackgroundResource(R.color.purple_700);}, 30);//30毫秒延迟break;default:break;}return super.onTouchEvent(event);}
}public class MainActivity extends FragmentActivity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);TestOverClick testLay findViewById(R.id.testLay);Button idBtnTest findViewById(R.id.idBtnTest);idBtnTest.setOnClickListener(v - Log.e(TAG, 点击了内容: ));testLay.setBtn(idBtnTest);}
}上面的注释简直是保姆级的了。
自定义 TestOverClick 嵌套了个子 Button 控件设置android:clickabletrue可点击设置属性android:clipChildrenfalse和android:clipToPaddingfalse实现超出区域可见。自定义 TestOverClick 有个方法 initClickRect 是用来设置点击响应区域的咱们向右侧进行了扩大红色为默认响应区域经过计算布局中控件是距离左300像素 控件本身是200 他俩的中间间距为100 加上按钮的本身宽度。右侧增加了绿框范围的响应区域。 接着我们在 onTouchEvent 函数中做两个处理处理一是判断下点击的区间通过计算允许在按钮范围内处理否则的话直接消耗事件这样就假装模拟出了只响应按钮了。处理二是在事件中抬起的时候回调下按钮的模拟点击事件就会进入业务逻辑。注意我们真正点击的其实是父控件只不过模拟点击了按钮。默认模拟点击是没有点击效果的所以我们在 onTouchEvent 中 down 和 up 的时候自己更改下按钮背景状态即可完美实现点击UI变化。activity 中直接使用即可我们内部需要用到按钮记得要传递进去按钮对象。
题外
一个Parent只能设置一个View的TouchDelegate设置多个时只有最后设置的生效。 如果想恢复 View 的触摸范围
/*** 还原View的触摸和点击响应范围,最小不小于View自身范围*/
public static void restoreViewTouchDelegate(final View view) {((View) view.getParent()).post(new Runnable() {Overridepublic void run() {Rect bounds new Rect();bounds.setEmpty();TouchDelegate touchDelegate new TouchDelegate(bounds, view);if (View.class.isInstance(view.getParent())) {((View) view.getParent()).setTouchDelegate(touchDelegate);}}});
}还没懂下方卡片联系我手把手教你。
其他 作者小空和小芝中的小空 转载说明-务必注明来源https://zhima.blog.csdn.net/ 这位道友请留步☁️我观你气度不凡谈吐间隐隐有王者霸气日后定有一番大作为旁边有点赞收藏今日传你点了吧未来你成功☀️我分文不取若不成功⚡️也好回来找我。 温馨提示点击下方卡片获取更多意想不到的资源。