Let’s start with an effect
Note the following points:
- Rounded corners
- Press the effect
- Same layout, two line effects and one line effects
- I have a 1px line on the outside
Perhaps I am uneducated, and finally with the help of others to achieve this effect.
There are several points to pay attention to:
- Rounded corners are custom controls
- The custom control controls whether there are lines in the outermost layer
- Click on the effect of
- How do you change a single line to a double line
- How to pop up the interface on the window,
The official start of the
-
Custom controls with rounded corners
- Copy available
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(a) { 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) { // Create layer A and draw the rounded corner matrix canvas.saveLayer(roundRect, zonePaint, Canvas.ALL_SAVE_FLAG); canvas.drawRoundRect(roundRect, rect_adius, rect_adius, zonePaint); // Create layer B and use xferMode to turn the shape of the layer into a rounded matrix canvas.saveLayer(roundRect, maskPaint, Canvas.ALL_SAVE_FLAG); // Empty the layer color canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); super.draw(canvas); // Draw layer B onto the canvas if(borderPaint ! =null) { canvas.drawRoundRect(roundRect, rect_adius, rect_adius, borderPaint); } canvas.restore(); } public void setCorner(float adius) { rect_adius = adius; invalidate(); }}Copy the code
- Copy available
-
Control lines
- Add this to attrs.xml to control the corner size and border size
<declare-styleable name="CornerLinearLayout"> <attr name="cornerRadius" /> <attr name="border_width" /> </declare-styleable> Copy the code
-
Click on the effect of
-
At the beginning really did not think of this effect to do, and then the great god said: transparent can. And so it looks like this. 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> Copy the code
-
After that, just set the background color for the click range.
<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="Cancel" /> Copy the code
-
-
A single line becomes a double line
-
The way I did it was to hide + resize components
<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="Cancel" /> </com.txznet.music.widget.CornerLinearLayout> Copy the code
-
Then make it a row. Just change the size of the outermost control to the size of the row. For example, the height of the single row is 72 [800×480 devices].
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); } Copy the code
-
-
Add to the main window to the screen
-
I am a 4.4 device, so the permissions are not considered, because the framework applies for all the 5.0 permissions by default
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); Copy the code
-
Simple adaptation scheme
-
You may have noticed that the width and length of the code or XML are set in @dimen/m120, because this is not the toutiao adaptation scheme, but the old scale method, which is to convert the values under different screen resolutions according to the base (800×480), for example: A 1px width above 800×480 equals a few pixels above 1024×600, and a 1px height equals a few pixels above 1024×600?
H = 1px * 600/480 = 1.25px w = 1px * 1024/800 = 1.28px
Maybe you will have a question [may have experienced to know, in the car environment inside a variety of strange equipment, impossible to prevent, some length is very long, but the height is very short, some height is very high, but the length is very short], that is not my a square picture will be drawn into a strange long bar. For example, the ratios 1.25 and 1.28 are converted to a minimum resolution. For example, the ratios 1.25 and 1.28 are converted to a minimum resolution. 1.25 and 1.28 we use the 1.25 rule, so we have a file like this: (of course, this file can be automatically generated in Java, just write the rules)
<?xml version="1.0" encoding="utf-8"? > <resources><dimen name="m1">1.25 px.</dimen> <dimen name="m2">2.5 px.</dimen> <dimen name="m3">3.75 px.</dimen> <dimen name="m4">5.0 px.</dimen> <dimen name="m5">6.25 px.</dimen> <dimen name="m6">7.5 px.</dimen> <dimen name="m7">8.75 px.</dimen> <dimen name="m8">10.0 px.</dimen> <dimen name="m9">11.25 px.</dimen> <dimen name="m10">12.5 px.</dimen> //m11 --- m469 <dimen name="m470">587.5 px.</dimen> <dimen name="m471">588.75 px.</dimen> <dimen name="m472">590.0 px.</dimen> <dimen name="m473">591.25 px.</dimen> <dimen name="m474">592.5 px.</dimen> <dimen name="m475">593.75 px.</dimen> <dimen name="m476">595.0 px.</dimen> <dimen name="m477">596.25 px.</dimen> <dimen name="m478">597.5 px.</dimen> <dimen name="m479">598.75 px.</dimen> <dimen name="m480">600.0 px.</dimen> </resources> Copy the code
-
Here is the Java code to generate the rules (the benchmarks can be changed, of course)
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 = "800480; 960540; 1280720; 1920108; 1280400; 1200400; 1280720; 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;" + "1280408; 694480; 650480; 1184384; 1024600; 1024720; 1920120; 1076736; 1000700; 480320"; 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()); }/ * * *@paramsupportStr * 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(a) { 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.0 f / baseW; StringBuffer sbForWidth = new StringBuffer(); sbForWidth.append(" \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.0 f / baseH; StringBuffer sbForHeight = new StringBuffer(); sbForHeight.append(" \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(" \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.0 f * 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); } newGenerateValueFiles(baseW, baseH, addition).generate(); }}Copy the code
-
We also need to dynamically calculate the number of columns that the GridView needs to fill, keep the position fixed instead of centered when the maximum number of columns can be filled is less than the maximum number of columns, and keep the left and right spacing equal when the maximum number of columns can be filled
mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout(a) { mRecyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this); int measuredWidth = mRecyclerView.getMeasuredWidth();// The total size of the control int startSize = getResources().getDimensionPixelOffset(R.dimen.m160);// The width of an Item int count = 1;// Maximum number of columns int spanSize = 0;// The remaining width for (int i = 0; i < 10; i++) { startSize += getResources().getDimensionPixelOffset(R.dimen.m24);// The spacing between items 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 = newGridLayoutManager(getContext(), count); gridLayoutManager.setOrientation(GridLayoutManager.VERTICAL); mRecyclerView.setLayoutManager(gridLayoutManager); }});Copy the code