圆角点击效果+适配

先从一个效果说起吧

注意下几点:
  1. 圆角
  2. 按下的效果
  3. 同一个布局,两行效果和一行效果
  4. 最外还有1px的线条

可能本人才疏学浅,最终是在别人的帮助才完成这个效果的。

一共需要注意的几个点:

  1. 圆角用的是自定义控件
  2. 自定义控件可以控制最外层是否有线条
  3. 点击效果
  4. 单行变双行,双行变单行怎么做到
  5. 如何弹出界面在window上面,
正式开始
  1. 圆角的自定义控件

    1. 复制可用
      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();
          }
      }
      复制代码
  2. 控制线条

    1. 在attrs.xml中加上这个来进行控制圆角大小以及边框大小
     <declare-styleable name="CornerLinearLayout">
             <attr name="cornerRadius" />
             <attr name="border_width" />
     </declare-styleable>
    复制代码
  3. 点击效果

    1. 一开始真的没有想到这个效果要怎么办,后来大神说:透明就可以了。于是就变成这样了。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>
      复制代码
    2. 之后只要对点击的范围设置背景色就好了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="取消" />
      复制代码
  4. 单行变双行

    1. 我用的方式是隐藏+改变组件大小

      <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>
      复制代码
    2. 然后变成一行只需要将最外层的控件大小改为一行的大小,比方说我这里设计师给到的单行的高度是: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);
          }
      复制代码
  5. 添加到主window到屏幕上

    1. 本人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);
      复制代码

简单适配方案

  1. 也许你注意到了代码里面或者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>
    
    复制代码
  2. 这里附上生成规则的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();
    	}
    
    }
    复制代码
  3. 这里还要讲下,动态计算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);
                }
            });
    复制代码

今天就到这里吧

猜你喜欢

转载自juejin.im/post/5c4d67106fb9a04a006f63c1