实现TextView拖拽显示
layout:
<LinearLayout android:id="@+id/rl" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/logo" android:text="张" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_bias="0.497" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.425" /> </LinearLayout>
tv.setOnTouchListener(new View.OnTouchListener() { int orgX, orgY; int offsetX, offsetY; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: orgX = (int) event.getX(); orgY = (int) event.getY(); Log.d("TAG", "onTouch: orgX=="+orgX); Log.d("TAG", "onTouch: orgY=="+orgY); break; case MotionEvent.ACTION_MOVE: offsetX = (int) event.getRawX() - orgX; offsetY = (int) event.getRawY() - orgY; Log.d("TAG", "onTouch: event.getRawX()=="+event.getRawX()); Log.d("TAG", "onTouch: event.getRawY()=="+event.getRawY()); Log.d("TAG", "offsetX: offsetX=="+offsetX); Log.d("TAG", "offsetY: offsetY=="+offsetY); LinearLayout.LayoutParams p1 = (LinearLayout.LayoutParams) relativeLayout.getLayoutParams(); p1.topMargin = offsetY;//设置像素 p1.leftMargin = offsetX;//设置像素 relativeLayout.setLayoutParams(p1); break; } return true; } });
补充:getRawX和get的区别
getX()是表示Widget相对于自身左上角的x坐标。
getRawX()是表示相对于屏幕左上角的x坐标值,这个屏幕左上角是手机屏幕左上角,不管activity是否有titleBar或是否全屏幕。
简单的自定义 View
package com.example.ceshi; import android.content.Context; import android.content.res.TypedArray; /** * @ProjectName: ceshi * @Package: com.example.ceshi * @ClassName: MyView * @Description: java类作用描述 * @Author: 作者名 * @CreateDate: 2020/7/30 0030 下午 5:22 * @UpdateUser: 更新者: * @UpdateDate: 2020/7/30 0030 下午 5:22 */ public class MyView extends View { private Paint myPaint; private Paint myPaint1; private static final String myString = "Hello CustomView!"; public MyView(Context context) { super(context); // TODO Auto-generated constructor stub } int bg; String text; int textColor1; public MyView(Context context, AttributeSet attr) { super(context, attr); myPaint = new Paint(); TypedArray a = context.obtainStyledAttributes(attr, R.styleable.myView);//TypedArray是一个数组容器 float textSize = a.getDimension(R.styleable.myView_textSize, 30);//防止在XML文件里没有定义,就加上了默认值30 int textColor = a.getColor(R.styleable.myView_textColor, 0x34343434);//同上,这里的属性是:名字_属性名 textColor1 = a.getColor(R.styleable.myView_textColor1, 0x34343434);//同上,这里的属性是:名字_属性名 bg = a.getColor(R.styleable.myView_backg, 0xdd0000);//同上,这里的属性是:名字_属性名 text = a.getString(R.styleable.myView_text); myPaint.setTextSize(textSize); myPaint.setColor(textColor); a.recycle();//我的理解是: // 返回以前取回的属性,供以后使用。以前取回的可能就是textSize和textColor初始化的那段 } /** * @param canvas */ @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); myPaint1 = new Paint(); myPaint1.setColor(textColor1); myPaint1.setColor(Color.BLUE); canvas.drawCircle(500, 500, 200, myPaint1); canvas.drawCircle(500, 500, 100, myPaint); canvas.drawText(text, 0, 0, myPaint); } }
layout:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tes="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <com.example.ceshi.MyView android:id="@+id/mv" android:layout_width="match_parent" android:layout_height="wrap_content" tes:text="zhangjiqun" tes:textColor="#ff0000" tes:textColor1="#FFF283" tes:textSize="50px"> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="张" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_bias="0.497" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.425" tools:text="张 " /> </com.example.ceshi.MyView> </LinearLayout>
调用并实现动画:
package com.example.ceshi; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; /** * */ public class MainActivity extends AppCompatActivity { private TextView tv; Handler handler = new Handler() { @Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: tv.setText(111 + ""); break; case 2: tv.setText(222 + ""); break; case 3: tv.setText(333 + ""); break; case 4: tv.setText(444 + ""); break; case 5: tv.setText(555 + ""); break; } } }; private ProgressDialog processDialog; /** * @param savedInstanceState */ @RequiresApi(api = Build.VERSION_CODES.KITKAT) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) findViewById(R.id.tv); final MyView myView=findViewById(R.id.mv); myView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this,"123", Toast.LENGTH_SHORT).show(); } }); handler.sendEmptyMessageDelayed(1, 1000); handler.sendEmptyMessageDelayed(2, 2000); handler.sendEmptyMessageDelayed(3, 3000); handler.sendEmptyMessageDelayed(4, 4000); handler.sendEmptyMessageDelayed(5, 5000); tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(MainActivity.this, MainActivityt.class); startActivity(intent); } }); ObjectAnimator objectAnimator=ObjectAnimator.ofFloat( myView, "alpha", 1f, 0f, 1f); objectAnimator.setDuration(2000).setStartDelay(100); ; objectAnimator.setRepeatCount(1000); objectAnimator.setRepeatMode(ValueAnimator.RESTART); objectAnimator.start(); ObjectAnimator objectAnimator1=ObjectAnimator.ofFloat(myView, "rotation",0f,360f); myView.setPivotX(400); myView.setPivotY(400); objectAnimator1.setRepeatCount(1000); objectAnimator1.setDuration(500).start(); float fl=myView.getTranslationX(); ObjectAnimator objectAnimator2=ObjectAnimator.ofFloat(myView, "scale",1f,3f,1f); objectAnimator2.setDuration(2000).setRepeatCount(2000); objectAnimator2.start(); ObjectAnimator objectAnimator3=ObjectAnimator.ofFloat(myView, "scaleX",1f,3f,1f); objectAnimator3.setDuration(2000).setRepeatCount(2000); objectAnimator3.start(); String a = "123"; tv.setText(a); try { Test(); } catch ( ServiceException e ) { // e.printStackTrace(); waitCloseAlert("执行线程异常,原因:"+e.getMessage()); } } public static void Test()throws ServiceException { throw new ServiceException("怎么说"); } /** * 关闭等待警告提示 * */ public void waitCloseAlert(final String message) { MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { if (processDialog != null && processDialog.isShowing()) { processDialog.dismiss(); } showAlertDialog(message,null,R.drawable.ic_launcher_background,null); } }); } public void showAlertDialog(String title,String message,Integer icon,final View focusView){ AlertDialog.Builder builder=new AlertDialog.Builder(this); if(title!=null){ builder.setTitle(title); } if(message!=null){ builder.setMessage(message); } if(icon!=null){ builder.setIcon(icon); } builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if(focusView!=null){ focusView.requestFocus(); } } }); AlertDialog dialog = builder.create(); dialog.show(); } }
xmlns 作用
xmlns:android="schemas.android.com/apk/res/and…
这个是xml的命名空间,也可以理解为语法文件。或者语法判断器什么的; 这个主要作用是在运行的时候那些控件的属性都是通过它来识别的,如果上面你写错了,不会有任何问题,但是在运行的时候就会有问题,提示你没有指定宽度等什么。这个是不用联网的。
自定义xmlns:xmlns:tes="http://schemas.android.com/apk/res-auto"
xmlns 使用,下面有两种形式,现在一般使用直接 res-auto;
Android attrs文件(自定义)属性详解
<!-- declare-styleable表示为自定义的属性--> <!-- format表示为可接受的参数类型--> <!--integer int型--> <!--boolean boolean--> <!--color 颜色--> <!--dimension 尺寸--> <!--enum 枚举--> <!--flag 位或运算--> <!--float float型--> <!--fraction 百分数--> <!--reference 资源文件--> <!--string 字符串--> <declare-styleable name="MyView"> <attr name="a" format="integer"></attr> <attr name="b" format="boolean"></attr> <attr name="c" format="color"></attr> <attr name="d" format="dimension"></attr> <attr name="e"></attr> <attr name="f"></attr> <attr name="g" format="float"></attr> <attr name="h" format="fraction"></attr> <attr name="i" format="reference"></attr> <attr name="j" format="string"></attr> </declare-styleable> <attr name="e"> <enum name="e1" value="1"></enum> <enum name="e2" value="2"></enum> </attr> <attr name="f"> <flag name="f1" value="1"></flag> <flag name="f2" value="2"></flag> </attr>
在layout头部设置:
xmlns:tes="http://schemas.android.com/apk/res-auto"
使用:
tes:textColor="#ff0000"
主要是使用一些图片资源的时候使用reference;
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="myView"> <attr name="backg" format="color" /> <attr name="textColor" format="color" /> <attr name="textColor1" format="color" /> <attr name="textSize" format="dimension" /> <attr name="text" format="string" /> <attr name="draw" format="reference" /> </declare-styleable> </resources> layout: <com.example.ceshi.MyView android:id="@+id/mv" android:layout_width="match_parent" android:layout_height="wrap_content" tes:draw="@drawable/ic_launcher_background" tes:text="zhangjiqun" tes:textColor="#ff0000" tes:textColor1="#FFF283" tes:textSize="50px"> </com.example.ceshi.MyView> 复制代码
draw = a.getResourceId(R.styleable.myView_draw, R.drawable.ic_launcher_background); Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_background); canvas.drawBitmap(mBitmap,100,100,myPaint);
整体:
package com.example.ceshi; import android.content.Context; /** * @ProjectName: ceshi * @Package: com.example.ceshi * @ClassName: MyView * @Description: java类作用描述 * @Author: 作者名 * @CreateDate: 2020/7/30 0030 下午 5:22 * @UpdateUser: 更新者: * @UpdateDate: 2020/7/30 0030 下午 5:22 */ public class MyView extends View { private Paint myPaint; private Paint myPaint1; private static final String myString = "Hello CustomView!"; public MyView(Context context) { super(context); // TODO Auto-generated constructor stub } int bg; String text; int textColor1; int draw; public MyView(Context context, AttributeSet attr) { super(context, attr); myPaint = new Paint(); TypedArray a = context.obtainStyledAttributes(attr, R.styleable.myView);//TypedArray是一个数组容器 float textSize = a.getDimension(R.styleable.myView_textSize, 30);//防止在XML文件里没有定义,就加上了默认值30 int textColor = a.getColor(R.styleable.myView_textColor, 0x34343434);//同上,这里的属性是:名字_属性名 draw = a.getResourceId(R.styleable.myView_draw, R.drawable.ic_launcher_background);//同上,这里的属性是:名字_属性名 textColor1 = a.getColor(R.styleable.myView_textColor1, 0x34343434);//同上,这里的属性是:名字_属性名 bg = a.getColor(R.styleable.myView_backg, 0xdd0000);//同上,这里的属性是:名字_属性名 text = a.getString(R.styleable.myView_text); myPaint.setTextSize(textSize); myPaint.setColor(textColor); a.recycle();//我的理解是: // 返回以前取回的属性,供以后使用。以前取回的可能就是textSize和textColor初始化的那段 } /** * @param canvas */ @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); myPaint1 = new Paint(); myPaint1.setColor(textColor1); myPaint1.setColor(Color.BLUE); canvas.drawCircle(500, 500, 200, myPaint1); canvas.drawCircle(500, 500, 100, myPaint); canvas.drawText(text, 0, 0, myPaint); Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), draw); canvas.drawBitmap(mBitmap,100,100,myPaint); } }
补充:drawable 转bitmap 空指针
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher_background);
上面这个是空指针,原因是这个资源文件是xml;
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.logo);
所以这个BitmapFactory必须使用图片资源才是可以的;
<declare-styleable name = "名称"> <attr name = "textColor" format = "color" /> </declare-styleable> eg: <TextView android:layout_width = "42dip" android:layout_height = "42dip" android:textColor = "#00FF00" />
补充:setColor方法:设置颜色
Color.RED:红色。 Color.TRANSPARENT:透明。 Color.WHITE:白色。 RGB颜色设置方法 setColor(new Color(int r,int g,int b)) 例如 setColor(new Color(220,255,220))
<declare-styleable name = "名称"> <attr name = "focusable" format = "boolean" /> </declare-styleable> eg: <Button android:layout_width = "42dip" android:layout_height = "42dip" android:focusable = "true"/>
<declare-styleable name = "名称"> <attr name = "layout_width" format = "dimension" /> </declare-styleable> eg: <com.lizi.newset.CustomView.attrs.MyView android:id="@+id/myView" android:layout_height="match_parent" android:layout_width="wrap_content" test:textSize="50px" test:textColor="#ff00ff"/>
<declare-styleable name = "AlphaAnimation"> <attr name = "fromAlpha" format = "float" /> <attr name = "toAlpha" format = "float" /> </declare-styleable> eg: <alpha android:fromAlpha = "1.0" android:toAlpha = "0.7" />
<declare-styleable name = "MapView"> <attr name = "apiKey" format = "string" /> </declare-styleable> eg: <com.google.android.maps.MapView android:layout_width = "fill_parent" android:layout_height = "fill_parent" android:apiKey = "0jOkQ80oD1JL9C6HAja99uGXCRiS2CGjKO_bc_g" />
<declare-styleable name = "AnimatedRotateDrawable"> <attr name = "visible" /> <attr name = "frameDuration" format="integer" /> <attr name = "framesCount" format="integer" /> <attr name = "pivotX" format = "fraction"/> <attr name = "pivotY" format = "fraction"/> <attr name = "drawable" /> </declare-styleable> eg: <animated-rotate xmlns:android = "http://schemas.android.com/apk/res/android" android:drawable = "@drawable/图片ID" android:pivotX = "50%" android:pivotY = "50%" android:framesCount = "12" android:frameDuration = "100" />
<declare-styleable name="名称"> <attr name="orientation"> <enum name="horizontal" value="0" /> <enum name="vertical" value="1" /> </attr> </declare-styleable> eg: <LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android" android:orientation = "vertical" android:layout_width = "fill_parent" android:layout_height = "fill_parent" > </LinearLayout>
<declare-styleable name="名称"> <attr name="windowSoftInputMode"> <flag name = "stateUnspecified" value = "0" /> <flag name = "stateUnchanged" value = "1" /> <flag name = "stateHidden" value = "2" /> <flag name = "stateAlwaysHidden" value = "3" /> <flag name = "stateVisible" value = "4" /> <flag name = "stateAlwaysVisible" value = "5" /> <flag name = "adjustUnspecified" value = "0x00" /> <flag name = "adjustResize" value = "0x10" /> <flag name = "adjustPan" value = "0x20" /> <flag name = "adjustNothing" value = "0x30" /> </attr> </declare-styleable> eg: <activity android:name = ".StyleAndThemeActivity" android:label = "@string/app_name" android:windowSoftInputMode = "stateUnspecified | stateUnchanged | stateHidden"> <intent-filter> <action android:name = "android.intent.action.MAIN" /> <category android:name = "android.intent.category.LAUNCHER" /> </intent-filter> </activity>
属性定义时可以同时定义多种类型值
<declare-styleable name = "名称"> <attr name = "background" format = "reference|color" /> </declare-styleable> eg: <ImageView android:layout_width = "42dip" android:layout_height = "42dip" android:background = "@drawable/图片ID|#00FF00" />
Error:(246, 5) error: invalid value '??' for ; must be an integer.
这个错诶就是在attrs中你有的地方赋值类型不对,仔细看看,我的 是有一个空格,但是类型是int;仔细检查;
Error:(369) duplicate value for resource 'attr/background' with config ''.
这是由于background这个值重复了,一般的都有这个数值,你改个名字;
属性动画:
旋转,缩放,透明度
ObjectAnimator objectAnimator=ObjectAnimator.ofFloat( myView, "alpha", 1f, 0f, 1f); objectAnimator.setDuration(2000).setStartDelay(100); ; objectAnimator.setRepeatCount(1000); objectAnimator.setRepeatMode(ValueAnimator.RESTART); objectAnimator.start(); ObjectAnimator objectAnimator1=ObjectAnimator.ofFloat(myView, "rotation",0f,360f); myView.setPivotX(400); myView.setPivotY(400); objectAnimator1.setRepeatCount(1000); objectAnimator1.setDuration(500).start(); float fl=myView.getTranslationX(); ObjectAnimator objectAnimator2=ObjectAnimator.ofFloat(myView, "scale",1f,3f,1f); objectAnimator2.setDuration(2000).setRepeatCount(2000); objectAnimator2.start(); ObjectAnimator objectAnimator3=ObjectAnimator.ofFloat(myView, "scaleX",1f,3f,1f); objectAnimator3.setDuration(2000).setRepeatCount(2000); objectAnimator3.start();
Android动态添加View之addView
layout:
<LinearLayout android:id="@+id/content" android:layout_width="match_parent" android:layout_height="66dp" android:orientation="horizontal"> </LinearLayout>
代码实现:
private LinearLayout mContainer; /** * 按钮点击事件,向容器中添加TextView * @param */ public void addView() { TextView child = new TextView(this); child.setTextSize(20); child.setTextColor(getResources().getColor(R.color.colorAccent)); // 获取当前的时间并转换为时间戳格式, 并设置给TextView child.setText("321"); // 调用一个参数的addView方法 mContainer.addView(child); }
自定义样式和主题
在工程中res/values/下添加styles.xml
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> <style name="CeShiTheme" parent="AppTheme"> <item name="android:typeface">monospace</item> </style> <style name="my_Style"> <!-- 定义与指定View相关的若干属性 --> <item name="android:hint">load from style 1</item> </style> <!-- 定义my_style_1,没有指定parent,用系统缺省的 --> <style name="my_style_1"> <!-- 定义与指定View相关的若干属性 --> <item name="android:hint">load from style 1</item> </style> <!-- 定义my_style_2,用自定义的my_style_1作为parent --> <style name="my_style_2" parent="@style/my_style_1"> <!-- 定义与指定View相关的若干属性 --> <item name="android:textSize">30sp</item> <item name="android:textColor">#FFFF0000</item> <item name="android:hint">load from style 2</item> </style> <!-- 定义my_style_3,用android的EditText作为parent --> <style name="my_style_3" parent="@android:style/Widget.EditText"> <!-- 定义与指定View相关的若干属性 --> <item name="android:hint">"load from style 3"</item> <item name="android:textStyle">bold|italic</item> <item name="android:typeface">monospace</item>> <item name="android:background">@drawable/logo</item> </style> <!-- 定义MyTheme,用android的Theme作为parent --> <style name="MyTheme" parent="@android:style/Theme"> <item name="android:textSize">20sp</item> <item name="android:textColor">#FF0000FF</item> <item name="android:hint">"load from style 3"</item> <item name="android:textStyle">bold|italic</item> <item name="android:typeface">monospace</item>> <item name="android:background">@drawable/logo</item> </style> </resources>