内容简介:可能本人才疏学浅,最终是在别人的帮助才完成这个效果的。一共需要注意的几个点:
- 圆角
- 按下的效果
- 同一个布局,两行效果和一行效果
- 最外还有1px的线条
可能本人才疏学浅,最终是在别人的帮助才完成这个效果的。
一共需要注意的几个点:
- 圆角用的是自定义控件
- 自定义控件可以控制最外层是否有线条
- 点击效果
- 单行变双行,双行变单行怎么做到
- 如何弹出界面在window上面,
正式开始
-
圆角的自定义控件
-
复制可用
public class CornerLinearLayout extends LinearLayout { private final RectF roundRect = new RectF(); private float rect_adius = getResources().getDimension(R.dimen.m2); private int borderWidth = 0; private final Paint maskPaint = new Paint(); private final Paint zonePaint = new Paint(); private Paint borderPaint = null; public CornerLinearLayout(@NonNull Context context) { this(context, null); } public CornerLinearLayout(@NonNull Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public CornerLinearLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); getAttrs(context, attrs); init(); } private void getAttrs(Context context, AttributeSet attrs) { TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CornerLinearLayout); rect_adius = ta.getDimension(R.styleable.CornerLinearLayout_cornerRadius, rect_adius); borderWidth = ta.getDimensionPixelOffset(R.styleable.CornerLinearLayout_border_width, -1); if (BuildConfig.DEBUG) { Log.d("telenewbie::", getClass().getSimpleName() + ",getAttrs" + borderWidth); } ta.recycle(); } private void init() { maskPaint.setAntiAlias(true); maskPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); zonePaint.setAntiAlias(true); zonePaint.setColor(Color.parseColor("#000000")); if (borderWidth > 0) { borderPaint = new Paint(); borderPaint.setStrokeWidth(borderWidth); borderPaint.setAntiAlias(true); borderPaint.setStyle(Paint.Style.STROKE); borderPaint.setColor(Color.parseColor("#19FFFFFF")); } float density = getResources().getDisplayMetrics().density; rect_adius = rect_adius * density; } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); int w = getWidth(); int h = getHeight(); roundRect.set(0, 0, w, h); } @Override public void draw(Canvas canvas) { // 创建图层A,绘制圆角矩阵 canvas.saveLayer(roundRect, zonePaint, Canvas.ALL_SAVE_FLAG); canvas.drawRoundRect(roundRect, rect_adius, rect_adius, zonePaint); // 创建图层B,使用xfermode将图层的形状变成圆角矩阵 canvas.saveLayer(roundRect, maskPaint, Canvas.ALL_SAVE_FLAG); // 清空图层的颜色 canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); super.draw(canvas); // 将图层B绘制到canvas上 if (borderPaint != null) { canvas.drawRoundRect(roundRect, rect_adius, rect_adius, borderPaint); } canvas.restore(); } public void setCorner(float adius) { rect_adius = adius; invalidate(); } } 复制代码
-
复制可用
-
控制线条
- 在attrs.xml中加上这个来进行控制圆角大小以及边框大小
<declare-styleable name="CornerLinearLayout"> <attr name="cornerRadius" /> <attr name="border_width" /> </declare-styleable> 复制代码
-
点击效果
-
一开始真的没有想到这个效果要怎么办,后来大神说:透明就可以了。于是就变成这样了。
base_dialog_btn_bg.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@color/white_10" android:state_pressed="true" /> <item android:drawable="@color/transparent" /> </selector> 复制代码
-
之后只要对点击的范围设置背景色就好了eg:
<TextView android:id="@+id/tv_cancel" android:layout_width="@dimen/m112" android:layout_height="match_parent" android:background="@drawable/base_dialog_btn_bg" android:gravity="center" android:textSize="@dimen/base_tv_h5" android:text="取消" /> 复制代码
-
-
单行变双行
-
我用的方式是隐藏+改变组件大小
<com.txznet.music.widget.CornerLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/rl_root" android:layout_width="match_parent" android:layout_height="@dimen/m112" android:layout_gravity="center_horizontal" android:layout_marginLeft="@dimen/m32" android:layout_marginRight="@dimen/m32" android:layout_marginTop="@dimen/m16" android:orientation="horizontal" android:background="@color/base_dialog_bg" app:border_width="@dimen/m1" app:cornerRadius="@dimen/m8"> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical"> <LinearLayout android:id="@+id/ll_first_range" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="@drawable/base_dialog_btn_bg" android:gravity="center_vertical" android:orientation="horizontal"> </LinearLayout> <View style="@style/Base_Divider_Horizontal" /> <LinearLayout android:id="@+id/ll_second_range" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="@drawable/base_dialog_btn_bg" android:gravity="center_vertical" android:orientation="horizontal" android:visibility="visible"> </LinearLayout> </LinearLayout> <View style="@style/Base_Divider_Vertical" /> <TextView android:id="@+id/tv_cancel" android:layout_width="@dimen/m112" android:layout_height="match_parent" android:background="@drawable/base_dialog_btn_bg" android:gravity="center" android:textSize="@dimen/base_tv_h5" android:text="取消" /> </com.txznet.music.widget.CornerLinearLayout> 复制代码
-
然后变成一行只需要将最外层的控件大小改为一行的大小,比方说我这里设计师给到的单行的高度是:72【800x480的设备】
private void changeLine(int style) { ViewGroup.LayoutParams layoutParams = mView.findViewById(R.id.rl_root).getLayoutParams(); if (layoutParams == null) { layoutParams = new WindowManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } if (STYLE_DOUBLE == style) { layoutParams.height = ((int) GlobalContext.get().getResources().getDimension(R.dimen.m112)); } else if (STYLE_SINGLE == style) { llSecondRange.setVisibility(GONE); layoutParams.height = ((int) GlobalContext.get().getResources().getDimension(R.dimen.m72)); } mView.findViewById(R.id.rl_root).setLayoutParams(layoutParams); } 复制代码
-
-
添加到主window到屏幕上
-
本人4.4的设备,所以权限方面没有考虑,因为框架默认申请5.0所有的权限
mWinManager = (WindowManager) GlobalContext.get().getSystemService(Context.WINDOW_SERVICE); mLayoutParam = new WindowManager.LayoutParams(); mLayoutParam.width = WindowManager.LayoutParams.MATCH_PARENT; mLayoutParam.height = WindowManager.LayoutParams.WRAP_CONTENT; mLayoutParam.type = WindowManager.LayoutParams.TYPE_PHONE; mLayoutParam.flags = 40; mLayoutParam.format = PixelFormat.RGBA_8888; mLayoutParam.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; mWinManager.addView(PushNotification.this, mLayoutParam); 复制代码
-
简单适配方案
-
也许你注意到了代码里面或者xml里面设置长宽都是采用
@dimen/m120
这样的方式来进行的,因为这里采用的不是今日头条的适配方案,而是再早之前的等比例缩放的方式即按照基准(800x480)来进行换算不同屏幕的分辨率底下的值,比方说:在800x480上面的宽 1px 相当于1024x600上面的几个像素,高1px相当于1024x600上面的多少个像素?经过换算需要显示的大小为:h = 1px * 600/480 = 1.25px w = 1px * 1024/800 = 1.28px
也许你会有疑问【可能经历过才知道,在车载环境里面各种奇葩的设备,防不胜防,有的长度很长,但高度很短,有的高度很高,但是长度很短】,那不是我一个正方形的图片会被拉成奇怪的长条状。正式因为考虑到这个【或者说遇到这个bug】,所以有了最小比例之说,比方说:上面的比例1.25 和1.28 我们就用最小的分辨率来进行换算生成一套最小的分辨率来进行设置,比方说:1.25和1.28我们就采用1.25的规则,于是就有了这样的一个文件:【当然这个文件可以通过 java 来进行自动生成,写好规则就好了】
<?xml version="1.0" encoding="utf-8"?> <resources><dimen name="m1">1.25px</dimen> <dimen name="m2">2.5px</dimen> <dimen name="m3">3.75px</dimen> <dimen name="m4">5.0px</dimen> <dimen name="m5">6.25px</dimen> <dimen name="m6">7.5px</dimen> <dimen name="m7">8.75px</dimen> <dimen name="m8">10.0px</dimen> <dimen name="m9">11.25px</dimen> <dimen name="m10">12.5px</dimen> //m11 --- m469 <dimen name="m470">587.5px</dimen> <dimen name="m471">588.75px</dimen> <dimen name="m472">590.0px</dimen> <dimen name="m473">591.25px</dimen> <dimen name="m474">592.5px</dimen> <dimen name="m475">593.75px</dimen> <dimen name="m476">595.0px</dimen> <dimen name="m477">596.25px</dimen> <dimen name="m478">597.5px</dimen> <dimen name="m479">598.75px</dimen> <dimen name="m480">600.0px</dimen> </resources> 复制代码
-
这里附上生成规则的java代码【当然基准是可以修改的】
public class GenerateValueFiles { private int baseW; private int baseH; private String dirStr = "./res"; private final static String WTemplate = "<dimen name=\"x{0}\">{1}px</dimen>\n"; private final static String HTemplate = "<dimen name=\"y{0}\">{1}px</dimen>\n"; private final static String SizeTemplate = "<dimen name=\"m{0}\">{1}px</dimen>\n"; /** * {0}-HEIGHT */ private final static String VALUE_TEMPLATE = "values-{0}x{1}"; private static final String SUPPORT_DIMESION = "800,480;960,540;1280,720;1920,1080;1280,400;1200,400;1280,720;2048," + "1536;1600,480;1280,480;854,480;480,272;800,432;1200,480;710,440;800,440;1920,480;980,400;1280,408;1280,352;" + "1280,408;694,480;650,480;1184,384;1024,600;1024,720;1920,1200;1076,736;1000,700;480,320"; private String supportStr = SUPPORT_DIMESION; public GenerateValueFiles(int baseX, int baseY, String supportStr) { this.baseW = baseX; this.baseH = baseY; if (!this.supportStr.contains(baseX + "," + baseY)) { this.supportStr += baseX + "," + baseY + ";"; } this.supportStr += validateInput(supportStr); System.out.println(supportStr); File dir = new File(dirStr); if (!dir.exists()) { dir.mkdir(); } System.out.println(dir.getAbsoluteFile()); } /** * @param supportStr * w,h_...w,h; * @return */ private String validateInput(String supportStr) { StringBuffer sb = new StringBuffer(); String[] vals = supportStr.split("_"); int w = -1; int h = -1; String[] wh; for (String val : vals) { try { if (val == null || val.trim().length() == 0) continue; wh = val.split(","); w = Integer.parseInt(wh[0]); h = Integer.parseInt(wh[1]); } catch (Exception e) { System.out.println("skip invalidate params : w,h = " + val); continue; } sb.append(w + "," + h + ";"); } return sb.toString(); } public void generate() { String[] vals = supportStr.split(";"); for (String val : vals) { String[] wh = val.split(","); generateXmlFile(Integer.parseInt(wh[0]), Integer.parseInt(wh[1])); } } private void generateXmlFile(int w, int h) { // float cellw = w * 1.0f / baseW; StringBuffer sbForWidth = new StringBuffer(); sbForWidth.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); sbForWidth.append("<resources>"); System.out.println("width : " + w + "," + baseW + "," + cellw ); for (int i = 1; i < baseW; i++) { sbForWidth.append(WTemplate.replace("{0}", i + "").replace("{1}", change(cellw * i) + "")); } sbForWidth.append(WTemplate.replace("{0}", baseW + "").replace("{1}", w + "")); sbForWidth.append("</resources>"); // float cellh = h * 1.0f / baseH; StringBuffer sbForHeight = new StringBuffer(); sbForHeight.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); sbForHeight.append("<resources>"); System.out.println("height : " + h + "," + baseH + "," + cellh); for (int i = 1; i < baseH; i++) { sbForHeight.append(HTemplate.replace("{0}", i + "").replace("{1}", change(cellh * i) + "")); } sbForHeight.append(HTemplate.replace("{0}", baseH + "").replace("{1}", h + "")); sbForHeight.append("</resources>"); // float minSize = (cellw < cellh) ? cellw : cellh; StringBuffer sbMinSize = new StringBuffer(); sbMinSize.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); sbMinSize.append("<resources>"); System.out.println("height : " + minSize + "," + cellw + "," + cellh); if(h<baseH){ for (int i = 1; i < baseH; i++) { sbMinSize.append(SizeTemplate.replace("{0}", i + "").replace("{1}", change(1.0f * i) + "")); } }else{ for (int i = 1; i < baseH; i++) { sbMinSize.append(SizeTemplate.replace("{0}", i + "").replace("{1}", change(minSize * i) + "")); } } sbMinSize.append(SizeTemplate.replace("{0}", ((cellw < cellh) ?baseW:baseH) + "").replace("{1}", ((cellw < cellh) ?w:h) + "")); sbMinSize.append("</resources>"); File fileDir = new File(dirStr + File.separator + VALUE_TEMPLATE.replace("{0}", w + "")// .replace("{1}", h + "")); fileDir.mkdir(); File layxFile = new File(fileDir.getAbsolutePath(), "lay_x.xml"); File layyFile = new File(fileDir.getAbsolutePath(), "lay_y.xml"); File laysizeFile = new File(fileDir.getAbsolutePath(), "lay_size.xml"); try { PrintWriter pw = new PrintWriter(new FileOutputStream(layxFile)); pw.print(sbForWidth.toString()); pw.close(); pw = new PrintWriter(new FileOutputStream(layyFile)); pw.print(sbForHeight.toString()); pw.close(); pw = new PrintWriter(new FileOutputStream(laysizeFile)); pw.print(sbMinSize.toString()); pw.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } } public static float change(float a) { int temp = (int) (a * 100); return temp / 100f; } public static void main(String[] args) { int baseW = 800; int baseH = 480; String addition = ""; try { if (args.length >= 3) { baseW = Integer.parseInt(args[0]); baseH = Integer.parseInt(args[1]); addition = args[2]; } else if (args.length >= 2) { baseW = Integer.parseInt(args[0]); baseH = Integer.parseInt(args[1]); } else if (args.length >= 1) { addition = args[0]; } } catch (NumberFormatException e) { System.err.println("right input params : java -jar xxx.jar width height w,h_w,h_..._w,h;"); e.printStackTrace(); System.exit(-1); } new GenerateValueFiles(baseW, baseH, addition).generate(); } } 复制代码
-
这里还要讲下,动态计算gridview需要填充的列数,在可填充的最大列数上呈现不足最大列数个数的时候保持位置固定而非居中,在呈现最大列数的时候能够保持左右间距相等
mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { mRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this); int measuredWidth = mRecyclerView.getMeasuredWidth();//控件总共拥有的空间大小 int startSize = getResources().getDimensionPixelOffset(R.dimen.m160);//一个Item的宽度 int count = 1;//最大的列数 int spanSize = 0;//剩余的宽度 for (int i = 0; i < 10; i++) { startSize += getResources().getDimensionPixelOffset(R.dimen.m24);//item与item之间的间距 startSize += getResources().getDimensionPixelOffset(R.dimen.m160); if (startSize > measuredWidth) { break; } spanSize = measuredWidth - startSize; count++; } if (BuildConfig.DEBUG) { Log.d("telenewbie::", getClass().getSimpleName() + ",onGlobalLayout:" + count + "," + startSize + "," + measuredWidth + "," + spanSize); } mRecyclerView.setPadding(spanSize / 2, 0, spanSize / 2, 0); GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), count); gridLayoutManager.setOrientation(GridLayoutManager.VERTICAL); mRecyclerView.setLayoutManager(gridLayoutManager); } }); 复制代码
以上所述就是小编给大家介绍的《圆角点击效果+适配》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
算法导论(原书第3版)
Thomas H.Cormen、Charles E.Leiserson、Ronald L.Rivest、Clifford Stein / 殷建平、徐云、王刚、刘晓光、苏明、邹恒明、王宏志 / 机械工业出版社 / 2012-12 / 128.00元
在有关算法的书中,有一些叙述非常严谨,但不够全面;另一些涉及了大量的题材,但又缺乏严谨性。本书将严谨性和全面性融为一体,深入讨论各类算法,并着力使这些算法的设计和分析能为各个层次的读者接受。全书各章自成体系,可以作为独立的学习单元;算法以英语和伪代码的形式描述,具备初步程序设计经验的人就能看懂;说明和解释力求浅显易懂,不失深度和数学严谨性。 全书选材经典、内容丰富、结构合理、逻辑清晰,对本科......一起来看看 《算法导论(原书第3版)》 这本书的介绍吧!