绘图与缩略完成

This commit is contained in:
ZhanGSKen 2025-02-22 19:43:11 +08:00
parent 3bcfc5a5da
commit 5e107028de
11 changed files with 400 additions and 16 deletions

View File

@ -49,7 +49,11 @@ android {
}
dependencies {
// 使
//
api 'com.google.android.gms:play-services-maps:18.1.0'
api 'com.google.android.gms:play-services-location:21.0.1'
// 使
api 'com.google.zxing:core:3.4.1'
api 'com.journeyapps:zxing-android-embedded:3.6.0'

View File

@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Fri Feb 21 17:45:58 GMT 2025
#Sat Feb 22 11:42:07 GMT 2025
stageCount=0
libraryProject=
baseVersion=1.0
publishVersion=1.0.0
buildCount=1
buildCount=54
baseBetaVersion=1.0.1

View File

@ -3,19 +3,33 @@
xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.winboll.studio.positions">
<!-- 只能在前台获取精确的位置信息 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- 只能在前台获取大概位置(基于网络) -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<application
android:name=".App"
android:allowBackup="true"
android:icon="@drawable/ic_winboll"
android:label="@string/app_name"
android:theme="@style/MyAppTheme"
android:supportsRtl="true">
android:supportsRtl="true"
android:hardwareAccelerated="true">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:exported="true">
</activity>
<activity
android:name=".activities.Main2Activity"
android:label="@string/app_name"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
@ -26,9 +40,8 @@
</activity>
<activity android:name="cc.winboll.studio.positions.activities.SettingsActivity"/>
<service
android:name="cc.winboll.studio.positions.services.MainService"
android:exported="true"/>
@ -44,7 +57,7 @@
</intent-filter>
</receiver>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"

View File

@ -146,7 +146,7 @@ final public class MainActivity extends AppCompatActivity implements IWinBollAct
void initData() {
ViewPager viewPager = findViewById(R.id.activitymainViewPager1);
LayoutInflater inflater = LayoutInflater.from(getActivity());
View view1 = inflater.inflate(R.layout.fragment_call, viewPager, false);
View view1 = inflater.inflate(R.layout.fragment_gms, viewPager, false);
View view2 = inflater.inflate(R.layout.fragment_contacts, viewPager, false);
View view3 = inflater.inflate(R.layout.fragment_log, viewPager, false);

View File

@ -0,0 +1,40 @@
package cc.winboll.studio.positions.activities;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/22 02:01:44
*/
import android.graphics.Color;
import android.os.Bundle;
import android.widget.Button;
import android.widget.FrameLayout;
import androidx.appcompat.app.AppCompatActivity;
import cc.winboll.studio.positions.R;
import cc.winboll.studio.positions.views.GridMapView;
import android.view.View.OnClickListener;
import android.view.View;
public class Main2Activity extends AppCompatActivity {
GridMapView gridMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
// 初始化视图
GridMapView mapView = (GridMapView) findViewById(R.id.map_view);
// 设置网格参数
mapView.setGridParameters(10000f, 10000f, 10f);
// 初始化显示区域中心点400,300显示范围200x200
mapView.initViewport(5000f, 5000f, 2000f, 2000f);
// 绘制图形
mapView.drawPoint(5000f, 5000f, Color.RED, 8f);
mapView.drawCircle(5000f, 5000f, 50f, Color.BLUE, 8f);
mapView.drawLine(4975f, 4975f, 5025f, 5025f, Color.GREEN, 2f);
}
}

View File

@ -9,7 +9,7 @@ import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import cc.winboll.studio.positions.fragments.CallFragment;
import cc.winboll.studio.positions.fragments.GmsFragment;
import cc.winboll.studio.positions.fragments.ContactsFragment;
import cc.winboll.studio.positions.fragments.LogFragment;
@ -30,7 +30,7 @@ public class MyPagerAdapter extends FragmentPagerAdapter {
} else if(position == 2) {
return LogFragment.newInstance(position);
} else {
return CallFragment.newInstance(position);
return GmsFragment.newInstance(position);
}
}

View File

@ -16,17 +16,17 @@ import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import android.widget.TextView;
public class CallFragment extends Fragment {
public class GmsFragment extends Fragment {
public static final String TAG = "CallFragment";
public static final String TAG = "GmsFragment";
private static final String ARG_PAGE = "ARG_PAGE";
private int mPage;
public static CallFragment newInstance(int page) {
public static GmsFragment newInstance(int page) {
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
CallFragment fragment = new CallFragment();
GmsFragment fragment = new GmsFragment();
fragment.setArguments(args);
return fragment;
}
@ -43,7 +43,7 @@ public class CallFragment extends Fragment {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_call, container, false);
View view = inflater.inflate(R.layout.fragment_gms, container, false);
TextView textView = view.findViewById(R.id.page_text);
textView.setText("这是第 " + mPage + "");
return view;

View File

@ -0,0 +1,246 @@
package cc.winboll.studio.positions.views;
/**
* @Author ZhanGSKen@AliYun.Com
* @Date 2025/02/22 03:32:48
* @Describe GridMapView
*/
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
public class GridMapView extends View {
// 网格参数
private float gridTotalWidth = 1000f;
private float gridTotalHeight = 1000f;
private float gridSpacing = 50f;
// 视图变换参数
private float offsetX = 0f;
private float offsetY = 0f;
private float scaleFactor = 1.0f;
private final float minScale = 0.5f;
private final float maxScale = 5.0f;
// 手势检测
private final ScaleGestureDetector scaleDetector;
private float lastTouchX;
private float lastTouchY;
// 图形存储
private final List<MapShape> shapes = new ArrayList<MapShape>();
public GridMapView(Context context) {
this(context, null);
}
public GridMapView(Context context, AttributeSet attrs) {
super(context, attrs);
scaleDetector = new ScaleGestureDetector(context, new ScaleListener());
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.translate(offsetX, offsetY);
canvas.scale(scaleFactor, scaleFactor);
drawGrid(canvas);
drawShapes(canvas);
canvas.restore();
}
private void drawGrid(Canvas canvas) {
Paint gridPaint = new Paint();
gridPaint.setColor(Color.LTGRAY);
gridPaint.setStrokeWidth(1f / scaleFactor);
// 绘制垂直线
for (float x = 0; x <= gridTotalWidth; x += gridSpacing) {
canvas.drawLine(x, 0, x, gridTotalHeight, gridPaint);
}
// 绘制水平线
for (float y = 0; y <= gridTotalHeight; y += gridSpacing) {
canvas.drawLine(0, y, gridTotalWidth, y, gridPaint);
}
}
private void drawShapes(Canvas canvas) {
for (MapShape shape : shapes) {
shape.draw(canvas);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
scaleDetector.onTouchEvent(event);
final int action = event.getAction();
final float x = event.getX();
final float y = event.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
if (!scaleDetector.isInProgress()) {
lastTouchX = x;
lastTouchY = y;
}
break;
case MotionEvent.ACTION_MOVE:
if (!scaleDetector.isInProgress()) {
final float dx = x - lastTouchX;
final float dy = y - lastTouchY;
offsetX += dx;
offsetY += dy;
invalidate();
lastTouchX = x;
lastTouchY = y;
}
break;
}
return true;
}
// 初始化视图显示区域
public void initViewport(final float centerX, final float centerY,
final float viewWidth, final float viewHeight) {
post(new Runnable() {
@Override
public void run() {
float viewportWidth = getWidth();
float viewportHeight = getHeight();
float widthScale = viewportWidth / viewWidth;
float heightScale = viewportHeight / viewHeight;
scaleFactor = Math.min(widthScale, heightScale);
offsetX = viewportWidth/2 - centerX * scaleFactor;
offsetY = viewportHeight/2 - centerY * scaleFactor;
invalidate();
}
});
}
// 图形绘制方法
public void drawPoint(float x, float y, int color, float size) {
shapes.add(new MapShape(MapShape.TYPE_POINT, x, y, color, size));
invalidate();
}
public void drawCircle(float x, float y, float radius, int color, float strokeWidth) {
MapShape shape = new MapShape(MapShape.TYPE_CIRCLE, x, y, color, radius);
shape.setStrokeWidth(strokeWidth);
shapes.add(shape);
invalidate();
}
public void drawLine(float startX, float startY, float endX, float endY,
int color, float strokeWidth) {
MapShape shape = new MapShape(MapShape.TYPE_LINE, startX, startY, endX, endY, color);
shape.setStrokeWidth(strokeWidth);
shapes.add(shape);
invalidate();
}
// 网格参数设置
public void setGridParameters(float totalWidth, float totalHeight, float spacing) {
gridTotalWidth = totalWidth;
gridTotalHeight = totalHeight;
gridSpacing = spacing;
invalidate();
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float newScale = scaleFactor * detector.getScaleFactor();
newScale = Math.max(minScale, Math.min(newScale, maxScale));
float focusX = detector.getFocusX();
float focusY = detector.getFocusY();
offsetX = focusX - ((focusX - offsetX) / scaleFactor * newScale);
offsetY = focusY - ((focusY - offsetY) / scaleFactor * newScale);
scaleFactor = newScale;
invalidate();
return true;
}
}
private static class MapShape {
static final int TYPE_POINT = 0;
static final int TYPE_CIRCLE = 1;
static final int TYPE_LINE = 2;
final int type;
final PointF[] points;
final int color;
float radius;
float strokeWidth = 2f;
MapShape(int type, float x, float y, int color, float size) {
this.type = type;
this.points = new PointF[]{new PointF(x, y)};
this.color = color;
this.radius = size;
}
MapShape(int type, float x1, float y1, float x2, float y2, int color) {
this.type = type;
this.points = new PointF[]{
new PointF(x1, y1),
new PointF(x2, y2)
};
this.color = color;
}
MapShape setStrokeWidth(float width) {
this.strokeWidth = width;
return this;
}
void draw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(color);
switch (type) {
case TYPE_POINT:
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(points[0].x, points[0].y, radius, paint);
break;
case TYPE_CIRCLE:
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(strokeWidth);
canvas.drawCircle(points[0].x, points[0].y, radius, paint);
break;
case TYPE_LINE:
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(strokeWidth);
canvas.drawLine(
points[0].x, points[0].y,
points[1].x, points[1].y,
paint
);
break;
}
}
}
}

View File

@ -0,0 +1,69 @@
<?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:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
android:background="#FFB2B2B2">
<Button
android:id="@+id/btn_get_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="获取位置"/>
<TextView
android:id="@+id/tv_latitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"/>
<TextView
android:id="@+id/tv_longitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"/>
<TextView
android:id="@+id/tv_altitude"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"/>
<TextView
android:id="@+id/tv_speed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"/>
<TextView
android:id="@+id/tv_bearing"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:orientation="vertical"
android:layout_weight="1.0">
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<cc.winboll.studio.positions.views.GridMapView
android:id="@+id/map_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="GridMapView">
<attr name="columns" format="integer" />
<attr name="rows" format="integer" />
<attr name="spacing" format="dimension" />
<attr name="initCenterX" format="float" />
<attr name="initCenterY" format="float" />
<attr name="initViewWidth" format="dimension" />
<attr name="initViewHeight" format="dimension" />
</declare-styleable>
</resources>