332
335 333
    @Override
334
    public void onGpsSignalWeak(boolean b) {
335
336
    }
337
338
    @Override
336 339
    public void onNaviSetting() {
337 340
338 341
    }
@ -387,4 +390,8 @@ public class BasicNaviActivity extends Activity implements AMapNaviListener, AMa
387 390
388 391
    }
389 392
393
    @Override
394
    public void onPointerCaptureChanged(boolean hasCapture) {
395
396
    }
390 397
}

+ 31 - 20
app/src/main/java/com/electric/chargingpile/activity/BuildMapActivity.java

@ -22,6 +22,7 @@ import com.amap.api.maps.UiSettings;
22 22
import com.amap.api.maps.model.CameraPosition;
23 23
import com.amap.api.maps.model.LatLng;
24 24
import com.amap.api.maps.model.MyLocationStyle;
25
import com.amap.api.services.core.AMapException;
25 26
import com.amap.api.services.core.LatLonPoint;
26 27
import com.amap.api.services.geocoder.GeocodeResult;
27 28
import com.amap.api.services.geocoder.GeocodeSearch;
@ -95,9 +96,14 @@ public class BuildMapActivity extends Activity implements View.OnClickListener,
95 96
            //获得地图的最大和最小缩放级别
96 97
            maxZoomLevel = aMap.getMaxZoomLevel();
97 98
            minZoomLevel = aMap.getMinZoomLevel();
98
            geocoderSearch = new GeocodeSearch(this);
99
            geocoderSearch.setOnGeocodeSearchListener(this);
100
            setUpMap();
99
            try {
100
                geocoderSearch = new GeocodeSearch(this);
101
                geocoderSearch.setOnGeocodeSearchListener(this);
102
                setUpMap();
103
            } catch (AMapException e) {
104
                e.printStackTrace();
105
            }
106
101 107
        }
102 108
    }
103 109
@ -342,23 +348,28 @@ public class BuildMapActivity extends Activity implements View.OnClickListener,
342 348
    public void activate(OnLocationChangedListener onLocationChangedListener) {
343 349
        mListener = onLocationChangedListener;
344 350
        if (mlocationClient == null) {
345
            mlocationClient = new AMapLocationClient(this);
346
            mLocationOption = new AMapLocationClientOption();
347
            //设置定位监听
348
            mlocationClient.setLocationListener(this);
349
            //设置为高精度定位模式
350
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
351
            //设置定位参数
352
            mlocationClient.setLocationOption(mLocationOption);
353
            // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
354
            // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
355
            // 在定位结束后,在合适的生命周期调用onDestroy()方法
356
            // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
357
            // 设置是否只定位一次,默认为false
358
            mLocationOption.setOnceLocation(true);
359
            //设置是否强制刷新WIFI,默认为强制刷新
360
            mLocationOption.setWifiActiveScan(false);
361
            mlocationClient.startLocation();
351
            try {
352
                mlocationClient = new AMapLocationClient(this);
353
                mLocationOption = new AMapLocationClientOption();
354
                //设置定位监听
355
                mlocationClient.setLocationListener(this);
356
                //设置为高精度定位模式
357
                mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
358
                //设置定位参数
359
                mlocationClient.setLocationOption(mLocationOption);
360
                // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
361
                // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
362
                // 在定位结束后,在合适的生命周期调用onDestroy()方法
363
                // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
364
                // 设置是否只定位一次,默认为false
365
                mLocationOption.setOnceLocation(true);
366
                //设置是否强制刷新WIFI,默认为强制刷新
367
                mLocationOption.setWifiActiveScan(false);
368
                mlocationClient.startLocation();
369
370
            } catch (Exception e) {
371
                e.printStackTrace();
372
            }
362 373
363 374
        }
364 375
    }

+ 22 - 17
app/src/main/java/com/electric/chargingpile/activity/ClaimMapActivity.java

@ -1607,23 +1607,28 @@ public class ClaimMapActivity extends Activity implements OnClickListener, AMap.
1607 1607
    public void activate(OnLocationChangedListener onLocationChangedListener) {
1608 1608
        mListener = onLocationChangedListener;
1609 1609
        if (mlocationClient == null) {
1610
            mlocationClient = new AMapLocationClient(this);
1611
            mLocationOption = new AMapLocationClientOption();
1612
            //设置定位监听
1613
            mlocationClient.setLocationListener(this);
1614
            //设置为高精度定位模式
1615
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
1616
            //设置定位参数
1617
            mlocationClient.setLocationOption(mLocationOption);
1618
            // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
1619
            // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
1620
            // 在定位结束后,在合适的生命周期调用onDestroy()方法
1621
            // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
1622
            // 设置是否只定位一次,默认为false
1623
            mLocationOption.setOnceLocation(true);
1624
            //设置是否强制刷新WIFI,默认为强制刷新
1625
            mLocationOption.setWifiActiveScan(false);
1626
            mlocationClient.startLocation();
1610
            try {
1611
                mlocationClient = new AMapLocationClient(this);
1612
                mLocationOption = new AMapLocationClientOption();
1613
                //设置定位监听
1614
                mlocationClient.setLocationListener(this);
1615
                //设置为高精度定位模式
1616
                mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
1617
                //设置定位参数
1618
                mlocationClient.setLocationOption(mLocationOption);
1619
                // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
1620
                // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
1621
                // 在定位结束后,在合适的生命周期调用onDestroy()方法
1622
                // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
1623
                // 设置是否只定位一次,默认为false
1624
                mLocationOption.setOnceLocation(true);
1625
                //设置是否强制刷新WIFI,默认为强制刷新
1626
                mLocationOption.setWifiActiveScan(false);
1627
                mlocationClient.startLocation();
1628
            } catch (Exception e) {
1629
                e.printStackTrace();
1630
            }
1631
1627 1632
1628 1633
        }
1629 1634
    }

+ 29 - 20
app/src/main/java/com/electric/chargingpile/activity/ClaimSurveyTwoActivity.java

@ -62,6 +62,7 @@ import com.amap.api.maps.model.LatLng;
62 62
import com.amap.api.maps.model.Marker;
63 63
import com.amap.api.maps.model.MarkerOptions;
64 64
import com.amap.api.maps.model.MyLocationStyle;
65
import com.amap.api.services.core.AMapException;
65 66
import com.amap.api.services.core.LatLonPoint;
66 67
import com.amap.api.services.geocoder.GeocodeResult;
67 68
import com.amap.api.services.geocoder.GeocodeSearch;
@ -2201,9 +2202,13 @@ public class ClaimSurveyTwoActivity extends Activity implements View.OnClickList
2201 2202
            //获得地图的最大和最小缩放级别
2202 2203
            maxZoomLevel = aMap.getMaxZoomLevel();
2203 2204
            minZoomLevel = aMap.getMinZoomLevel();
2204
            geocoderSearch = new GeocodeSearch(this);
2205
            geocoderSearch.setOnGeocodeSearchListener(this);
2206
            setUpMap();
2205
            try {
2206
                geocoderSearch = new GeocodeSearch(this);
2207
                geocoderSearch.setOnGeocodeSearchListener(this);
2208
                setUpMap();
2209
            } catch (AMapException e) {
2210
                e.printStackTrace();
2211
            }
2207 2212
        }
2208 2213
    }
2209 2214
@ -2234,23 +2239,27 @@ public class ClaimSurveyTwoActivity extends Activity implements View.OnClickList
2234 2239
    public void activate(OnLocationChangedListener onLocationChangedListener) {
2235 2240
        mListener = onLocationChangedListener;
2236 2241
        if (mlocationClient == null) {
2237
            mlocationClient = new AMapLocationClient(this);
2238
            mLocationOption = new AMapLocationClientOption();
2239
            //设置定位监听
2240
            mlocationClient.setLocationListener(this);
2241
            //设置为高精度定位模式
2242
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
2243
            //设置定位参数
2244
            mlocationClient.setLocationOption(mLocationOption);
2245
            // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
2246
            // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
2247
            // 在定位结束后,在合适的生命周期调用onDestroy()方法
2248
            // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
2249
            // 设置是否只定位一次,默认为false
2250
            mLocationOption.setOnceLocation(true);
2251
            //设置是否强制刷新WIFI,默认为强制刷新
2252
            mLocationOption.setWifiActiveScan(false);
2253
            mlocationClient.startLocation();
2242
            try {
2243
                mlocationClient = new AMapLocationClient(this);
2244
                mLocationOption = new AMapLocationClientOption();
2245
                //设置定位监听
2246
                mlocationClient.setLocationListener(this);
2247
                //设置为高精度定位模式
2248
                mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
2249
                //设置定位参数
2250
                mlocationClient.setLocationOption(mLocationOption);
2251
                // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
2252
                // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
2253
                // 在定位结束后,在合适的生命周期调用onDestroy()方法
2254
                // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
2255
                // 设置是否只定位一次,默认为false
2256
                mLocationOption.setOnceLocation(true);
2257
                //设置是否强制刷新WIFI,默认为强制刷新
2258
                mLocationOption.setWifiActiveScan(false);
2259
                mlocationClient.startLocation();
2260
            } catch (Exception e) {
2261
                e.printStackTrace();
2262
            }
2254 2263
        }
2255 2264
    }
2256 2265

+ 43 - 40
app/src/main/java/com/electric/chargingpile/activity/MainMapActivity.java

@ -1401,7 +1401,7 @@ public class MainMapActivity extends Activity implements LocationSource, AMapLoc
1401 1401
1402 1402
        changeButton();
1403 1403
1404
        if (hasLocationPermission() && center == null) {
1404
        if (hasLocationPermission() && center == null && mlocationClient!=null) {
1405 1405
            mlocationClient.startLocation();
1406 1406
        }
1407 1407
    }
@ -1504,62 +1504,65 @@ public class MainMapActivity extends Activity implements LocationSource, AMapLoc
1504 1504
    public void activate(OnLocationChangedListener listener) {
1505 1505
        mListener = listener;
1506 1506
        if (mlocationClient == null) {
1507
            mlocationClient = new AMapLocationClient(this);
1507
            try {
1508
                mlocationClient = new AMapLocationClient(this);
1508 1509
1509
            mLocationOption = new AMapLocationClientOption();
1510
            //设置定位监听
1511
            mlocationClient.setLocationListener(this);
1512
            //设置为高精度定位模式
1513
            mLocationOption.setLocationMode(AMapLocationMode.Battery_Saving);
1510
                mLocationOption = new AMapLocationClientOption();
1511
                //设置定位监听
1512
                mlocationClient.setLocationListener(this);
1513
                //设置为高精度定位模式
1514
                mLocationOption.setLocationMode(AMapLocationMode.Battery_Saving);
1514 1515
//            mLocationOption.setGpsFirst(true);
1515 1516
//            mLocationOption.setOnceLocation(true);
1516
            mLocationOption.setInterval(1500);
1517
                mLocationOption.setInterval(1500);
1517 1518
1518
            //设置是否强制刷新WIFI,默认为强制刷新
1519
                //设置是否强制刷新WIFI,默认为强制刷新
1519 1520
//            mLocationOption.setWifiActiveScan(true);
1520
            //设置定位参数
1521
            mlocationClient.setLocationOption(mLocationOption);
1522
            // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
1523
            // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
1524
            // 在定位结束后,在合适的生命周期调用onDestroy()方法
1525
            // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
1526
            // 设置是否只定位一次,默认为false
1527
            mLocationOption.setOnceLocation(false);
1528
            //设置是否强制刷新WIFI,默认为强制刷新
1529
            //mLocationOption.setWifiActiveScan(false);
1530
            mLocationOption.setWifiScan(true);
1531
1532
            if (ProfileManager.getInstance().getStartedRequestLocationPermission(MainMapActivity.this)) {
1533
                if (hasLocationPermission()) {
1534
                    requestLocationPermission();
1535
                }
1536
            } else { // 首次启动
1521
                //设置定位参数
1522
                mlocationClient.setLocationOption(mLocationOption);
1523
                // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
1524
                // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
1525
                // 在定位结束后,在合适的生命周期调用onDestroy()方法
1526
                // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
1527
                // 设置是否只定位一次,默认为false
1528
                mLocationOption.setOnceLocation(false);
1529
                //设置是否强制刷新WIFI,默认为强制刷新
1530
                //mLocationOption.setWifiActiveScan(false);
1531
                mLocationOption.setWifiScan(true);
1532
                if (ProfileManager.getInstance().getStartedRequestLocationPermission(MainMapActivity.this)) {
1533
                    if (hasLocationPermission()) {
1534
                        requestLocationPermission();
1535
                    }
1536
                } else { // 首次启动
1537 1537
1538
                ProfileManager.getInstance().setStartedRequestLocationPermission(MainMapActivity.this, true);
1539
                new LocationPermissionsDialog(context)
1540
                        .builder()
1541
                        .setMsg("需要确定您所在的城市,首页才能显示您所在的城市的站点信息,请您授权定位")
1542
                        .setLeftButton("取消",v -> {
1538
                    ProfileManager.getInstance().setStartedRequestLocationPermission(MainMapActivity.this, true);
1539
                    new LocationPermissionsDialog(context)
1540
                            .builder()
1541
                            .setMsg("需要确定您所在的城市,首页才能显示您所在的城市的站点信息,请您授权定位")
1542
                            .setLeftButton("取消",v -> {
1543 1543
1544
                        })
1545
                        .setRightButton("确定",v->{
1544
                            })
1545
                            .setRightButton("确定",v->{
1546 1546
                                EasyPermissions.requestPermissions(
1547 1547
                                        this,
1548 1548
                                        "为了定位您的位置,推荐充电桩,充电桩位置路线导航需要开启位置权限,是否前往开启?",
1549 1549
                                        RC_Location_FIRST_PERM,
1550 1550
                                        Manifest.permission.ACCESS_FINE_LOCATION,
1551 1551
                                        Manifest.permission.ACCESS_COARSE_LOCATION
1552
                                        );
1552
                                );
1553 1553
1554
                        }).show();
1554
                            }).show();
1555 1555
1556
            }
1556
                }
1557 1557
1558
            if (hasLocationPermission()) {
1559
                Log.e(TAG, "onResume: hyc 4" );
1560
                requestLocationPermission();
1561
            }
1558
                if (hasLocationPermission()) {
1559
                    Log.e(TAG, "onResume: hyc 4" );
1560
                    requestLocationPermission();
1561
                }
1562 1562
1563
            } catch (Exception e) {
1564
                e.printStackTrace();
1565
            }
1563 1566
        }
1564 1567
    }
1565 1568

+ 31 - 26
app/src/main/java/com/electric/chargingpile/activity/NewSelectCityActivity.java

@ -397,35 +397,40 @@ public class NewSelectCityActivity extends AppCompatActivity implements ISelectC
397 397
    }
398 398
399 399
    private void initLocation() {
400
        mlocationClient = new AMapLocationClient(this);
401
        //初始化定位参数
402
        mLocationOption = new AMapLocationClientOption();
403
        //设置定位监听
404
        mlocationClient.setLocationListener(this);
405
        //设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
406
        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
407
        mLocationOption.setOnceLocation(true);
408
        //设置是否强制刷新WIFI,默认为强制刷新
409
        mLocationOption.setWifiActiveScan(false);
410
        //设置定位间隔,单位毫秒,默认为2000ms
411
        // mLocationOption.setInterval(2000);
412
        // 设置定位参数
413
        mlocationClient.setLocationOption(mLocationOption);
414
        // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
415
        // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
416
        // 在定位结束后,在合适的生命周期调用onDestroy()方法
417
        // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
418
        //启动定位
419
420
        if (hasLocationPermission()) {
421
            requestLocationPermission();
422
        } else {
423
            mTvLocation.setText("定位失败");
424
            if (!ProfileManager.getInstance().getFirstRequestLocationPermission(NewSelectCityActivity.this)) {
425
                ProfileManager.getInstance().setFirstRequestLocationPermission(NewSelectCityActivity.this, true);
400
        try {
401
            mlocationClient = new AMapLocationClient(this);
402
            //初始化定位参数
403
            mLocationOption = new AMapLocationClientOption();
404
            //设置定位监听
405
            mlocationClient.setLocationListener(this);
406
            //设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
407
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
408
            mLocationOption.setOnceLocation(true);
409
            //设置是否强制刷新WIFI,默认为强制刷新
410
            mLocationOption.setWifiActiveScan(false);
411
            //设置定位间隔,单位毫秒,默认为2000ms
412
            // mLocationOption.setInterval(2000);
413
            // 设置定位参数
414
            mlocationClient.setLocationOption(mLocationOption);
415
            // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
416
            // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
417
            // 在定位结束后,在合适的生命周期调用onDestroy()方法
418
            // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
419
            //启动定位
420
421
            if (hasLocationPermission()) {
426 422
                requestLocationPermission();
423
            } else {
424
                mTvLocation.setText("定位失败");
425
                if (!ProfileManager.getInstance().getFirstRequestLocationPermission(NewSelectCityActivity.this)) {
426
                    ProfileManager.getInstance().setFirstRequestLocationPermission(NewSelectCityActivity.this, true);
427
                    requestLocationPermission();
428
                }
427 429
            }
430
        } catch (Exception e) {
431
            e.printStackTrace();
428 432
        }
433
429 434
    }
430 435
431 436
    private void insertData(CityRecord cityRecord) {

+ 19 - 14
app/src/main/java/com/electric/chargingpile/activity/OfflineMapActivity.java

@ -238,20 +238,25 @@ public class OfflineMapActivity extends Activity implements
238 238
        mAllOfflineMapList = (ExpandableListView) provinceContainer
239 239
                .findViewById(R.id.province_download_list);
240 240
241
        amapManager = new OfflineMapManager(this, this);
242
243
        initProvinceListAndCityMap();
244
245
        // adapter = new OfflineListAdapter(provinceList, cityMap, amapManager,
246
        // OfflineMapActivity.this);
247
        adapter = new OfflineListAdapter(provinceList, amapManager,
248
                OfflineMapActivity.this);
249
        // 为列表绑定数据源
250
        mAllOfflineMapList.setAdapter(adapter);
251
        // adapter实现了扩展列表的展开与合并监听
252
        mAllOfflineMapList.setOnGroupCollapseListener(adapter);
253
        mAllOfflineMapList.setOnGroupExpandListener(adapter);
254
        mAllOfflineMapList.setGroupIndicator(null);
241
        try {
242
            amapManager = new OfflineMapManager(this, this);
243
244
            initProvinceListAndCityMap();
245
246
            // adapter = new OfflineListAdapter(provinceList, cityMap, amapManager,
247
            // OfflineMapActivity.this);
248
            adapter = new OfflineListAdapter(provinceList, amapManager,
249
                    OfflineMapActivity.this);
250
            // 为列表绑定数据源
251
            mAllOfflineMapList.setAdapter(adapter);
252
            // adapter实现了扩展列表的展开与合并监听
253
            mAllOfflineMapList.setOnGroupCollapseListener(adapter);
254
            mAllOfflineMapList.setOnGroupExpandListener(adapter);
255
            mAllOfflineMapList.setGroupIndicator(null);
256
        } catch (Exception e) {
257
            e.printStackTrace();
258
        }
259
255 260
    }
256 261
257 262
    /**

+ 40 - 35
app/src/main/java/com/electric/chargingpile/activity/PileDetailsActivity.java

@ -348,43 +348,48 @@ public class PileDetailsActivity extends AppCompatActivity implements View.OnCli
348 348
        final AMapLocationClient mlocationClient;
349 349
        //声明mLocationOption对象
350 350
        AMapLocationClientOption mLocationOption = null;
351
        mlocationClient = new AMapLocationClient(this);
352
        //初始化定位参数
353
        mLocationOption = new AMapLocationClientOption();
354
        //设置定位监听
355
        mlocationClient.setLocationListener(new AMapLocationListener() {
356
            @Override
357
            public void onLocationChanged(AMapLocation amapLocation) {
358
                if (amapLocation != null) {
359
                    if (amapLocation.getErrorCode() == 0) {
360
                        //定位成功回调信息,设置相关消息
361
                        amapLocation.getLocationType();//获取当前定位结果来源,如网络定位结果,详见定位类型表
362
                        amapLocation.getLatitude();//获取纬度
363
                        amapLocation.getLongitude();//获取
364
                        amapLocation.getAccuracy();//获取精度信息
365
                        LogUtils.e(amapLocation.getLatitude() + "--" + amapLocation.getLongitude());
366
                        mlocationClient.stopLocation();
367
                        sendControlParkingDownLock(amapLocation, pileData);
368
                    } else {
369
                        //显示错误信息ErrCode是错误码,errInfo是错误信息,详见错误码表。
370
                        Log.e("AmapError", "location Error, ErrCode:"
371
                                + amapLocation.getErrorCode() + ", errInfo:"
372
                                + amapLocation.getErrorInfo());
351
        try {
352
            mlocationClient = new AMapLocationClient(this);
353
            //初始化定位参数
354
            mLocationOption = new AMapLocationClientOption();
355
            //设置定位监听
356
            mlocationClient.setLocationListener(new AMapLocationListener() {
357
                @Override
358
                public void onLocationChanged(AMapLocation amapLocation) {
359
                    if (amapLocation != null) {
360
                        if (amapLocation.getErrorCode() == 0) {
361
                            //定位成功回调信息,设置相关消息
362
                            amapLocation.getLocationType();//获取当前定位结果来源,如网络定位结果,详见定位类型表
363
                            amapLocation.getLatitude();//获取
364
                            amapLocation.getLongitude();//获取经度
365
                            amapLocation.getAccuracy();//获取精度信息
366
                            LogUtils.e(amapLocation.getLatitude() + "--" + amapLocation.getLongitude());
367
                            mlocationClient.stopLocation();
368
                            sendControlParkingDownLock(amapLocation, pileData);
369
                        } else {
370
                            //显示错误信息ErrCode是错误码,errInfo是错误信息,详见错误码表。
371
                            Log.e("AmapError", "location Error, ErrCode:"
372
                                    + amapLocation.getErrorCode() + ", errInfo:"
373
                                    + amapLocation.getErrorInfo());
374
                        }
373 375
                    }
374 376
                }
375
            }
376
        });
377
        //设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
378
        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
379
        //设置定位间隔,单位毫秒,默认为2000ms//        mLocationOption.setInterval(2000);
380
        //设置定位参数
381
        mlocationClient.setLocationOption(mLocationOption);
382
        // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
383
        // 注意设置合适的定位时间的间隔(最小间隔支持为1000ms),并且在合适时间调用stopLocation()方法来取消定位请求
384
        // 在定位结束后,在合适的生命周期调用onDestroy()方法
385
        // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
386
        //启动定位
387
        mlocationClient.startLocation();
377
            });
378
            //设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
379
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
380
            //设置定位间隔,单位毫秒,默认为2000ms//        mLocationOption.setInterval(2000);
381
            //设置定位参数
382
            mlocationClient.setLocationOption(mLocationOption);
383
            // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
384
            // 注意设置合适的定位时间的间隔(最小间隔支持为1000ms),并且在合适时间调用stopLocation()方法来取消定位请求
385
            // 在定位结束后,在合适的生命周期调用onDestroy()方法
386
            // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
387
            //启动定位
388
            mlocationClient.startLocation();
389
        } catch (Exception e) {
390
            e.printStackTrace();
391
        }
392
388 393
    }
389 394
390 395
    private void sendControlParkingDownLock(AMapLocation amapLocation, PileData pileData) {

+ 0 - 1
app/src/main/java/com/electric/chargingpile/activity/PrivacyAgreementActivity.java

@ -37,7 +37,6 @@ public class PrivacyAgreementActivity extends Activity {
37 37
        setContentView(R.layout.activity_privacy_agreement);
38 38
        BarColorUtil.initStatusBarColor(PrivacyAgreementActivity.this);
39 39
        if (ProfileManager.getInstance().getPrivacyAgreement(this)) {
40
            MainApplication.initSDK();
41 40
            Log.e("TAG_HYC", "onCreate:  getPrivacyAgreement" );
42 41
            startActivity(new Intent(PrivacyAgreementActivity.this, WelcomeActivity.class));
43 42
            finish();

+ 30 - 20
app/src/main/java/com/electric/chargingpile/activity/PrivateZhuangMapActivity.java

@ -29,6 +29,7 @@ import com.amap.api.maps.model.BitmapDescriptorFactory;
29 29
import com.amap.api.maps.model.CameraPosition;
30 30
import com.amap.api.maps.model.LatLng;
31 31
import com.amap.api.maps.model.MyLocationStyle;
32
import com.amap.api.services.core.AMapException;
32 33
import com.amap.api.services.core.LatLonPoint;
33 34
import com.amap.api.services.geocoder.GeocodeResult;
34 35
import com.amap.api.services.geocoder.GeocodeSearch;
@ -126,9 +127,13 @@ public class PrivateZhuangMapActivity extends Activity implements View.OnClickLi
126 127
            //获得地图的最大和最小缩放级别
127 128
            maxZoomLevel = aMap.getMaxZoomLevel();
128 129
            minZoomLevel = aMap.getMinZoomLevel();
129
            geocoderSearch = new GeocodeSearch(this);
130
            geocoderSearch.setOnGeocodeSearchListener(this);
131
            setUpMap();
130
            try {
131
                geocoderSearch = new GeocodeSearch(this);
132
                geocoderSearch.setOnGeocodeSearchListener(this);
133
                setUpMap();
134
            } catch (AMapException e) {
135
                e.printStackTrace();
136
            }
132 137
        }
133 138
    }
134 139
@ -432,23 +437,28 @@ public class PrivateZhuangMapActivity extends Activity implements View.OnClickLi
432 437
    public void activate(OnLocationChangedListener onLocationChangedListener) {
433 438
        mListener = onLocationChangedListener;
434 439
        if (mlocationClient == null) {
435
            mlocationClient = new AMapLocationClient(this);
436
            mLocationOption = new AMapLocationClientOption();
437
            //设置定位监听
438
            mlocationClient.setLocationListener(this);
439
            //设置为高精度定位模式
440
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
441
            //设置定位参数
442
            mlocationClient.setLocationOption(mLocationOption);
443
            // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
444
            // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
445
            // 在定位结束后,在合适的生命周期调用onDestroy()方法
446
            // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
447
            // 设置是否只定位一次,默认为false
448
            mLocationOption.setOnceLocation(true);
449
            //设置是否强制刷新WIFI,默认为强制刷新
450
            mLocationOption.setWifiActiveScan(false);
451
            mlocationClient.startLocation();
440
            try {
441
                mlocationClient = new AMapLocationClient(this);
442
                mLocationOption = new AMapLocationClientOption();
443
                //设置定位监听
444
                mlocationClient.setLocationListener(this);
445
                //设置为高精度定位模式
446
                mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
447
                //设置定位参数
448
                mlocationClient.setLocationOption(mLocationOption);
449
                // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
450
                // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
451
                // 在定位结束后,在合适的生命周期调用onDestroy()方法
452
                // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
453
                // 设置是否只定位一次,默认为false
454
                mLocationOption.setOnceLocation(true);
455
                //设置是否强制刷新WIFI,默认为强制刷新
456
                mLocationOption.setWifiActiveScan(false);
457
                mlocationClient.startLocation();
458
459
            } catch (Exception e) {
460
                e.printStackTrace();
461
            }
452 462
453 463
        }
454 464
    }

+ 25 - 20
app/src/main/java/com/electric/chargingpile/activity/RecommendZhanActivity.java

@ -361,31 +361,36 @@ public class RecommendZhanActivity extends Activity implements View.OnClickListe
361 361
    public void activate(OnLocationChangedListener onLocationChangedListener) {
362 362
        mListener = onLocationChangedListener;
363 363
        if (mlocationClient == null) {
364
            mlocationClient = new AMapLocationClient(this);
364
            try {
365
                mlocationClient = new AMapLocationClient(this);
365 366
366
            mLocationOption = new AMapLocationClientOption();
367
            //设置定位监听
368
            mlocationClient.setLocationListener(this);
369
            //设置为高精度定位模式
370
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Battery_Saving);
367
                mLocationOption = new AMapLocationClientOption();
368
                //设置定位监听
369
                mlocationClient.setLocationListener(this);
370
                //设置为高精度定位模式
371
                mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Battery_Saving);
371 372
//            mLocationOption.setGpsFirst(true);
372 373
//            mLocationOption.setOnceLocation(true);
373
            mLocationOption.setInterval(1500);
374
                mLocationOption.setInterval(1500);
374 375
375
            //设置是否强制刷新WIFI,默认为强制刷新
376
                //设置是否强制刷新WIFI,默认为强制刷新
376 377
//            mLocationOption.setWifiActiveScan(true);
377
            //设置定位参数
378
            mlocationClient.setLocationOption(mLocationOption);
379
            // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
380
            // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
381
            // 在定位结束后,在合适的生命周期调用onDestroy()方法
382
            // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
383
            // 设置是否只定位一次,默认为false
384
            mLocationOption.setOnceLocation(false);
385
386
            //设置是否强制刷新WIFI,默认为强制刷新
387
            mLocationOption.setWifiActiveScan(false);
388
            mlocationClient.startLocation();
378
                //设置定位参数
379
                mlocationClient.setLocationOption(mLocationOption);
380
                // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
381
                // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
382
                // 在定位结束后,在合适的生命周期调用onDestroy()方法
383
                // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
384
                // 设置是否只定位一次,默认为false
385
                mLocationOption.setOnceLocation(false);
386
387
                //设置是否强制刷新WIFI,默认为强制刷新
388
                mLocationOption.setWifiActiveScan(false);
389
                mlocationClient.startLocation();
390
391
            } catch (Exception e) {
392
                e.printStackTrace();
393
            }
389 394
390 395
        }
391 396
    }

+ 58 - 80
app/src/main/java/com/electric/chargingpile/activity/RoutePlanMapActivity.java

@ -68,7 +68,7 @@ import com.amap.api.navi.model.AMapLaneInfo;
68 68
import com.amap.api.navi.model.AMapModelCross;
69 69
import com.amap.api.navi.model.AMapNaviCameraInfo;
70 70
import com.amap.api.navi.model.AMapNaviCross;
71
import com.amap.api.navi.model.AMapNaviInfo;
71
72 72
import com.amap.api.navi.model.AMapNaviLocation;
73 73
import com.amap.api.navi.model.AMapNaviPath;
74 74
import com.amap.api.navi.model.AMapNaviRouteNotifyData;
@ -80,13 +80,14 @@ import com.amap.api.navi.model.AimLessModeStat;
80 80
import com.amap.api.navi.model.NaviInfo;
81 81
import com.amap.api.navi.model.NaviLatLng;
82 82
import com.amap.api.navi.view.RouteOverLay;
83
import com.amap.api.services.core.AMapException;
83 84
import com.amap.api.services.core.LatLonPoint;
84 85
import com.amap.api.services.core.PoiItem;
85 86
import com.amap.api.services.geocoder.GeocodeResult;
86 87
import com.amap.api.services.geocoder.GeocodeSearch;
87 88
import com.amap.api.services.geocoder.RegeocodeQuery;
88 89
import com.amap.api.services.geocoder.RegeocodeResult;
89
import com.autonavi.tbt.TrafficFacilityInfo;
90
90 91
import com.blankj.utilcode.util.EmptyUtils;
91 92
import com.blankj.utilcode.util.LogUtils;
92 93
import com.blankj.utilcode.util.SizeUtils;
@ -414,16 +415,26 @@ public class RoutePlanMapActivity extends Activity implements LocationSource, AM
414 415
        if (amap == null) {
415 416
            amap = mapView.getMap();
416 417
            Util.setMapCustomStyleFile(amap, getApplicationContext());
417
            aMapNavi = AMapNavi.getInstance(getApplicationContext());
418
            aMapNavi.addAMapNaviListener(this);
419
            aMapNavi.setUseInnerVoice(true);
420
            MyLocationStyle myLocationStyle = new MyLocationStyle();
421
            myLocationStyle.myLocationIcon(com.amap.api.maps.model.BitmapDescriptorFactory.fromResource(R.drawable.point_icon));// 设置小蓝点的图标
422
            amap.setMyLocationStyle(myLocationStyle);
418
            try {
419
                aMapNavi = AMapNavi.getInstance(getApplicationContext());
420
                aMapNavi.addAMapNaviListener(this);
421
                aMapNavi.setUseInnerVoice(true);
422
                MyLocationStyle myLocationStyle = new MyLocationStyle();
423
                myLocationStyle.myLocationIcon(com.amap.api.maps.model.BitmapDescriptorFactory.fromResource(R.drawable.point_icon));// 设置小蓝点的图标
424
                amap.setMyLocationStyle(myLocationStyle);
425
            } catch (com.amap.api.maps.AMapException e) {
426
                e.printStackTrace();
427
            }
428
423 429
            //获得地图的最大和最小缩放级别
424
            geocoderSearch = new GeocodeSearch(this);
425
            geocoderSearch.setOnGeocodeSearchListener(this);
426
            setUpMap();
430
            try {
431
                geocoderSearch = new GeocodeSearch(this);
432
                geocoderSearch.setOnGeocodeSearchListener(this);
433
                setUpMap();
434
            } catch (AMapException e) {
435
                e.printStackTrace();
436
            }
437
427 438
428 439
        }
429 440
    }
@ -747,12 +758,12 @@ public class RoutePlanMapActivity extends Activity implements LocationSource, AM
747 758
            routeOverLay.setStartPointBitmap(drawableToBitamp(getResources().getDrawable(R.drawable.icon_newstarr)));
748 759
            routeOverLay.setEndPointBitmap(drawableToBitamp(getResources().getDrawable(R.drawable.icon_newstopr)));
749 760
            routeOverLay.setWayPointBitmap(drawableToBitamp(getResources().getDrawable(R.drawable.icon_zhanwei)));
750
            routeOverLay.setTrafficLightsVisible(false);
761
            //routeOverLay.setTrafficLightsVisible(false);
751 762
            routeOverLay.addToMap();
752 763
            routeOverlays.put(routeIds[i], routeOverLay);
753 764
            routeOverLay.getAMapNaviPath().getSteps();
754 765
755
            routePlanInfo.setNo(routeOverlays.get(routeIds[i]).getAMapNaviPath().getStrategy() + "");
766
            routePlanInfo.setNo(routeOverlays.get(routeIds[i]).getAMapNaviPath().getLabels() + "");
756 767
            routePlanInfo.setTime(routeOverlays.get(routeIds[i]).getAMapNaviPath().getAllTime() + "");
757 768
            routePlanInfo.setDistance(routeOverlays.get(routeIds[i]).getAMapNaviPath().getAllLength() + "");
758 769
@ -857,15 +868,8 @@ public class RoutePlanMapActivity extends Activity implements LocationSource, AM
857 868
        int i = l.size();
858 869
859 870
        if (i == 1) {
860
            if (l.get(0).getNo().equals("0")) {
861
                tv_route_no1.setText("推荐");
862
            } else if (l.get(0).getNo().equals("2")) {
863
                tv_route_no1.setText("距离最短");
864
            } else if (l.get(0).getNo().equals("4")) {
865
                tv_route_no1.setText("时间最短");
866
            } else {
867
                tv_route_no1.setText("其他方案");
868
            }
871
            tv_route_no1.setText(l.get(0).getNo());
872
869 873
            tv_route_distance1.setText(getMToKm(l.get(0).getDistance()));
870 874
            tv_route_time1.setText(getSToHm(l.get(0).getTime()));
871 875
            rl_route2.setVisibility(View.GONE);
@ -873,26 +877,13 @@ public class RoutePlanMapActivity extends Activity implements LocationSource, AM
873 877
            view1.setVisibility(View.GONE);
874 878
            view2.setVisibility(View.GONE);
875 879
        } else if (i == 2) {
876
            if (l.get(0).getNo().equals("0")) {
877
                tv_route_no1.setText("推荐");
878
            } else if (l.get(0).getNo().equals("2")) {
879
                tv_route_no1.setText("距离最短");
880
            } else if (l.get(0).getNo().equals("4")) {
881
                tv_route_no1.setText("时间最短");
882
            } else {
883
                tv_route_no1.setText("其他方案");
884
            }
880
            tv_route_no1.setText(l.get(0).getNo());
881
885 882
            tv_route_distance1.setText(getMToKm(l.get(0).getDistance()));
886 883
            tv_route_time1.setText(getSToHm(l.get(0).getTime()));
887
            if (l.get(1).getNo().equals("0")) {
888
                tv_route_no2.setText("推荐");
889
            } else if (l.get(1).getNo().equals("2")) {
890
                tv_route_no2.setText("距离最短");
891
            } else if (l.get(1).getNo().equals("4")) {
892
                tv_route_no2.setText("时间最短");
893
            } else {
894
                tv_route_no2.setText("其他方案");
895
            }
884
885
            tv_route_no2.setText(l.get(1).getNo());
886
896 887
            tv_route_distance2.setText(getMToKm(l.get(1).getDistance()));
897 888
            tv_route_time2.setText(getSToHm(l.get(1).getTime()));
898 889
@ -906,38 +897,18 @@ public class RoutePlanMapActivity extends Activity implements LocationSource, AM
906 897
            view2.setVisibility(View.VISIBLE);
907 898
            rl_route2.setVisibility(View.VISIBLE);
908 899
            view1.setVisibility(View.VISIBLE);
909
            if (l.get(0).getNo().equals("0")) {
910
                tv_route_no1.setText("推荐");
911
            } else if (l.get(0).getNo().equals("2")) {
912
                tv_route_no1.setText("距离最短");
913
            } else if (l.get(0).getNo().equals("4")) {
914
                tv_route_no1.setText("时间最短");
915
            } else {
916
                tv_route_no1.setText("其他方案");
917
            }
900
901
            tv_route_no1.setText(l.get(0).getNo());
902
918 903
            tv_route_distance1.setText(getMToKm(l.get(0).getDistance()));
919 904
            tv_route_time1.setText(getSToHm(l.get(0).getTime()));
920 905
921
            if (l.get(1).getNo().equals("0")) {
922
                tv_route_no2.setText("推荐");
923
            } else if (l.get(1).getNo().equals("2")) {
924
                tv_route_no2.setText("距离最短");
925
            } else if (l.get(1).getNo().equals("4")) {
926
                tv_route_no2.setText("时间最短");
927
            } else {
928
                tv_route_no2.setText("其他方案");
929
            }
906
907
            tv_route_no2.setText(l.get(1).getNo());
908
930 909
            tv_route_distance2.setText(getMToKm(l.get(1).getDistance()));
931 910
            tv_route_time2.setText(getSToHm(l.get(1).getTime()));
932
            if (l.get(2).getNo().equals("0")) {
933
                tv_route_no3.setText("推荐");
934
            } else if (l.get(2).getNo().equals("2")) {
935
                tv_route_no3.setText("距离最短");
936
            } else if (l.get(2).getNo().equals("4")) {
937
                tv_route_no3.setText("时间最短");
938
            } else {
939
                tv_route_no3.setText("其他方案");
940
            }
911
            tv_route_no3.setText(l.get(2).getNo());
941 912
            tv_route_distance3.setText(getMToKm(l.get(2).getDistance()));
942 913
            tv_route_time3.setText(getSToHm(l.get(2).getTime()));
943 914
        }
@ -1004,6 +975,11 @@ public class RoutePlanMapActivity extends Activity implements LocationSource, AM
1004 975
    public void onNaviRouteNotify(AMapNaviRouteNotifyData aMapNaviRouteNotifyData) {
1005 976
    }
1006 977
978
    @Override
979
    public void onGpsSignalWeak(boolean b) {
980
981
    }
982
1007 983
1008 984
    public void changeRoute(View view) {
1009 985
        if (mMarkerCity != null) {
@ -1509,10 +1485,6 @@ public class RoutePlanMapActivity extends Activity implements LocationSource, AM
1509 1485
1510 1486
    }
1511 1487
1512
    @Override
1513
    public void onNaviInfoUpdated(AMapNaviInfo naviInfo) {
1514
1515
    }
1516 1488
1517 1489
    @Override
1518 1490
    public void updateCameraInfo(AMapNaviCameraInfo[] aMapNaviCameraInfos) {
@ -1535,10 +1507,7 @@ public class RoutePlanMapActivity extends Activity implements LocationSource, AM
1535 1507
1536 1508
    }
1537 1509
1538
    @Override
1539
    public void OnUpdateTrafficFacility(TrafficFacilityInfo trafficFacilityInfo) {
1540 1510
1541
    }
1542 1511
1543 1512
    @Override
1544 1513
    public void OnUpdateTrafficFacility(AMapNaviTrafficFacilityInfo aMapNaviTrafficFacilityInfo) {
@ -1605,7 +1574,11 @@ public class RoutePlanMapActivity extends Activity implements LocationSource, AM
1605 1574
    public void activate(OnLocationChangedListener onLocationChangedListener) {
1606 1575
        mListener = onLocationChangedListener;
1607 1576
        if (mlocationClient == null) {
1608
            mlocationClient = new AMapLocationClient(this);
1577
            try {
1578
                mlocationClient = new AMapLocationClient(this);
1579
            } catch (Exception e) {
1580
                e.printStackTrace();
1581
            }
1609 1582
            mLocationOption = new AMapLocationClientOption();
1610 1583
            //设置定位监听
1611 1584
            mlocationClient.setLocationListener(this);
@ -1854,7 +1827,7 @@ public class RoutePlanMapActivity extends Activity implements LocationSource, AM
1854 1827
                        routeOverLay.setStartPointBitmap(drawableToBitamp(getResources().getDrawable(R.drawable.icon_route_start)));
1855 1828
                        routeOverLay.setEndPointBitmap(drawableToBitamp(getResources().getDrawable(R.drawable.icon_route_end)));
1856 1829
                        routeOverLay.setWayPointBitmap(drawableToBitamp(getResources().getDrawable(R.drawable.icon_zhanwei)));
1857
                        routeOverLay.setTrafficLightsVisible(false);
1830
                        //routeOverLay.setTrafficLightsVisible(false);
1858 1831
                        routeOverLay.addToMap();
1859 1832
                        routeOverlays.put(routeIds[i], routeOverLay);
1860 1833
                    }
@ -1916,7 +1889,7 @@ public class RoutePlanMapActivity extends Activity implements LocationSource, AM
1916 1889
                        routeOverLay.setStartPointBitmap(drawableToBitamp(getResources().getDrawable(R.drawable.icon_route_start)));
1917 1890
                        routeOverLay.setEndPointBitmap(drawableToBitamp(getResources().getDrawable(R.drawable.icon_route_end)));
1918 1891
                        routeOverLay.setWayPointBitmap(drawableToBitamp(getResources().getDrawable(R.drawable.icon_zhanwei)));
1919
                        routeOverLay.setTrafficLightsVisible(false);
1892
                        //routeOverLay.setTrafficLightsVisible(false);
1920 1893
                        routeOverLay.addToMap();
1921 1894
                        routeOverlays.put(routeIds[i], routeOverLay);
1922 1895
                    }
@ -1976,7 +1949,7 @@ public class RoutePlanMapActivity extends Activity implements LocationSource, AM
1976 1949
                        routeOverLay.setStartPointBitmap(drawableToBitamp(getResources().getDrawable(R.drawable.icon_newstarr)));
1977 1950
                        routeOverLay.setEndPointBitmap(drawableToBitamp(getResources().getDrawable(R.drawable.icon_newstopr)));
1978 1951
                        routeOverLay.setWayPointBitmap(drawableToBitamp(getResources().getDrawable(R.drawable.icon_zhanwei)));
1979
                        routeOverLay.setTrafficLightsVisible(false);
1952
                        //routeOverLay.setTrafficLightsVisible(false);
1980 1953
                        routeOverLay.addToMap();
1981 1954
                        routeOverlays.put(routeIds[i], routeOverLay);
1982 1955
                    }
@ -2065,7 +2038,7 @@ public class RoutePlanMapActivity extends Activity implements LocationSource, AM
2065 2038
                            routeOverLay.setStartPointBitmap(BitmapFactory.decodeResource(this.getResources(), R.drawable.icon_newstarr));
2066 2039
                            routeOverLay.setEndPointBitmap(BitmapFactory.decodeResource(this.getResources(), R.drawable.icon_newstopr));
2067 2040
                            routeOverLay.setWayPointBitmap(BitmapFactory.decodeResource(this.getResources(), R.drawable.icon_zhanwei));
2068
                            routeOverLay.setTrafficLightsVisible(false);
2041
                            //routeOverLay.setTrafficLightsVisible(false);
2069 2042
                            routeOverlays.put(routeIds[i], routeOverLay);
2070 2043
                            routeOverLay.addToMap();
2071 2044
                        }
@ -2933,7 +2906,7 @@ public class RoutePlanMapActivity extends Activity implements LocationSource, AM
2933 2906
                routeOverLay.setStartPointBitmap(drawableToBitamp(getResources().getDrawable(R.drawable.icon_newstarr)));
2934 2907
                routeOverLay.setEndPointBitmap(drawableToBitamp(getResources().getDrawable(R.drawable.icon_newstopr)));
2935 2908
                routeOverLay.setWayPointBitmap(drawableToBitamp(getResources().getDrawable(R.drawable.icon_zhanwei)));
2936
                routeOverLay.setTrafficLightsVisible(false);
2909
                //routeOverLay.setTrafficLightsVisible(false);
2937 2910
                routeOverLay.addToMap();
2938 2911
                routeOverlays.put(routeIds[i], routeOverLay);
2939 2912
            }
@ -2990,4 +2963,9 @@ public class RoutePlanMapActivity extends Activity implements LocationSource, AM
2990 2963
    public View getInfoContents(Marker marker) {
2991 2964
        return null;
2992 2965
    }
2966
2967
    @Override
2968
    public void onPointerCaptureChanged(boolean hasCapture) {
2969
2970
    }
2993 2971
}

+ 11 - 3
app/src/main/java/com/electric/chargingpile/activity/RoutePlanSelectAddressActivity.java

@ -1,6 +1,7 @@
1 1
package com.electric.chargingpile.activity;
2 2
3 3
4
import android.annotation.SuppressLint;
4 5
import android.app.Activity;
5 6
import android.content.ContentValues;
6 7
import android.content.Context;
@ -28,6 +29,7 @@ import android.widget.SimpleCursorAdapter;
28 29
import android.widget.TextView;
29 30
import android.widget.Toast;
30 31
32
import com.amap.api.services.core.AMapException;
31 33
import com.amap.api.services.core.PoiItem;
32 34
import com.amap.api.services.core.SuggestionCity;
33 35
import com.amap.api.services.poisearch.PoiResult;
@ -96,6 +98,7 @@ public class RoutePlanSelectAddressActivity extends Activity implements View.OnC
96 98
//        Toast.makeText(getApplicationContext(),tag,Toast.LENGTH_SHORT).show();
97 99
    }
98 100
101
    @SuppressLint("Range")
99 102
    private void initViews() {
100 103
        rl_mapselect = (RelativeLayout) findViewById(R.id.rl_mapselect);
101 104
        rl_mapselect.setOnClickListener(this);
@ -455,9 +458,14 @@ public class RoutePlanSelectAddressActivity extends Activity implements View.OnC
455 458
        query.setPageSize(20);// 设置每页最多返回多少条poiitem
456 459
        query.setPageNum(currentPage);// 设置查第一页
457 460
458
        poiSearch = new PoiSearch(this, query);
459
        poiSearch.setOnPoiSearchListener(this);
460
        poiSearch.searchPOIAsyn();
461
        try {
462
            poiSearch = new PoiSearch(this, query);
463
            poiSearch.setOnPoiSearchListener(this);
464
            poiSearch.searchPOIAsyn();
465
        } catch (AMapException e) {
466
            e.printStackTrace();
467
        }
468
461 469
    }
462 470
463 471
    @Override

+ 30 - 20
app/src/main/java/com/electric/chargingpile/activity/RouteSelectPointActivity.java

@ -26,6 +26,7 @@ import com.amap.api.maps.UiSettings;
26 26
import com.amap.api.maps.model.CameraPosition;
27 27
import com.amap.api.maps.model.LatLng;
28 28
import com.amap.api.maps.model.MyLocationStyle;
29
import com.amap.api.services.core.AMapException;
29 30
import com.amap.api.services.core.LatLonPoint;
30 31
import com.amap.api.services.core.PoiItem;
31 32
import com.amap.api.services.geocoder.GeocodeResult;
@ -122,9 +123,13 @@ public class RouteSelectPointActivity extends Activity implements View.OnClickLi
122 123
            //获得地图的最大和最小缩放级别
123 124
            maxZoomLevel = aMap.getMaxZoomLevel();
124 125
            minZoomLevel = aMap.getMinZoomLevel();
125
            geocoderSearch = new GeocodeSearch(this);
126
            geocoderSearch.setOnGeocodeSearchListener(this);
127
            setUpMap();
126
            try {
127
                geocoderSearch = new GeocodeSearch(this);
128
                geocoderSearch.setOnGeocodeSearchListener(this);
129
                setUpMap();
130
            } catch (AMapException e) {
131
                e.printStackTrace();
132
            }
128 133
        }
129 134
    }
130 135
@ -267,23 +272,28 @@ public class RouteSelectPointActivity extends Activity implements View.OnClickLi
267 272
    public void activate(OnLocationChangedListener onLocationChangedListener) {
268 273
        mListener = onLocationChangedListener;
269 274
        if (mlocationClient == null) {
270
            mlocationClient = new AMapLocationClient(this);
271
            mLocationOption = new AMapLocationClientOption();
272
            //设置定位监听
273
            mlocationClient.setLocationListener(this);
274
            //设置为高精度定位模式
275
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
276
            //设置定位参数
277
            mlocationClient.setLocationOption(mLocationOption);
278
            // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
279
            // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
280
            // 在定位结束后,在合适的生命周期调用onDestroy()方法
281
            // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
282
            // 设置是否只定位一次,默认为false
283
            mLocationOption.setOnceLocation(true);
284
            //设置是否强制刷新WIFI,默认为强制刷新
285
            mLocationOption.setWifiActiveScan(false);
286
            mlocationClient.startLocation();
275
            try {
276
                mlocationClient = new AMapLocationClient(this);
277
                mLocationOption = new AMapLocationClientOption();
278
                //设置定位监听
279
                mlocationClient.setLocationListener(this);
280
                //设置为高精度定位模式
281
                mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
282
                //设置定位参数
283
                mlocationClient.setLocationOption(mLocationOption);
284
                // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
285
                // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
286
                // 在定位结束后,在合适的生命周期调用onDestroy()方法
287
                // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
288
                // 设置是否只定位一次,默认为false
289
                mLocationOption.setOnceLocation(true);
290
                //设置是否强制刷新WIFI,默认为强制刷新
291
                mLocationOption.setWifiActiveScan(false);
292
                mlocationClient.startLocation();
293
294
            } catch (Exception e) {
295
                e.printStackTrace();
296
            }
287 297
288 298
        }
289 299
    }

+ 9 - 3
app/src/main/java/com/electric/chargingpile/activity/SearchActivity.java

@ -42,6 +42,7 @@ import android.widget.Toast;
42 42

43 43
import com.amap.api.maps.AMapUtils;
44 44
import com.amap.api.maps.model.LatLng;
45
import com.amap.api.services.core.AMapException;
45 46
import com.amap.api.services.core.PoiItem;
46 47
import com.amap.api.services.core.SuggestionCity;
47 48
import com.amap.api.services.help.Inputtips;
@ -912,9 +913,14 @@ public class SearchActivity extends Activity implements OnClickListener, Inputti
912 913
        query.setPageSize(30);// 设置每页最多返回多少条poiitem
913 914
        query.setPageNum(currentPage);// 设置查第一页
914 915

915
        poiSearch = new PoiSearch(this, query);
916
        poiSearch.setOnPoiSearchListener(this);
917
        poiSearch.searchPOIAsyn();
916
        try {
917
            poiSearch = new PoiSearch(this, query);
918
            poiSearch.setOnPoiSearchListener(this);
919
            poiSearch.searchPOIAsyn();
920
        } catch (AMapException e) {
921
            e.printStackTrace();
922
        }
923

918 924
    }
919 925

920 926
    private void doPointNameSearchQuery() {

+ 16 - 11
app/src/main/java/com/electric/chargingpile/activity/SelectCityActivity.java

@ -293,7 +293,7 @@ public class SelectCityActivity extends Activity implements AMapLocationListener
293 293
        SQLiteDatabase recentVisitDb = cityOpenHelper.getWritableDatabase();
294 294
        Cursor cursor = recentVisitDb.rawQuery("select * from recentcity order by date desc limit 0, 3", null);
295 295
        while (cursor.moveToNext()) {
296
            String recentVisitCityName = cursor.getString(cursor.getColumnIndex("name"));
296
            @SuppressLint("Range") String recentVisitCityName = cursor.getString(cursor.getColumnIndex("name"));
297 297
            recentCityList.add(recentVisitCityName);
298 298
        }
299 299
        cursor.close();
@ -599,27 +599,32 @@ public class SelectCityActivity extends Activity implements AMapLocationListener
599 599
    private void setUpMap() {
600 600
//        //声明mLocationOption对象
601 601
//        AMapLocationClientOption mLocationOption = null;
602
        mlocationClient = new AMapLocationClient(this);
603
//初始化定位参数
604
        mLocationOption = new AMapLocationClientOption();
602
        try {
603
            mlocationClient = new AMapLocationClient(this);
604
            //初始化定位参数
605
            mLocationOption = new AMapLocationClientOption();
605 606
//设置定位监听
606
        mlocationClient.setLocationListener(this);
607
            mlocationClient.setLocationListener(this);
607 608
//设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
608
        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
609
        mLocationOption.setOnceLocation(true);
610
        //设置是否强制刷新WIFI,默认为强制刷新
611
        mLocationOption.setWifiActiveScan(false);
609
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
610
            mLocationOption.setOnceLocation(true);
611
            //设置是否强制刷新WIFI,默认为强制刷新
612
            mLocationOption.setWifiActiveScan(false);
612 613
//设置定位间隔,单位毫秒,默认为2000ms
613 614
//        mLocationOption.setInterval(2000);
614 615
//设置定位参数
615
        mlocationClient.setLocationOption(mLocationOption);
616
            mlocationClient.setLocationOption(mLocationOption);
616 617
// 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
617 618
// 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
618 619
// 在定位结束后,在合适的生命周期调用onDestroy()方法
619 620
// 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
620 621
621 622
//启动定位
622
        mlocationClient.startLocation();
623
            mlocationClient.startLocation();
624
        } catch (Exception e) {
625
            e.printStackTrace();
626
        }
627
623 628
    }
624 629
625 630

+ 31 - 20
app/src/main/java/com/electric/chargingpile/activity/ShareMapActivity.java

@ -28,6 +28,7 @@ import com.amap.api.maps.model.BitmapDescriptorFactory;
28 28
import com.amap.api.maps.model.CameraPosition;
29 29
import com.amap.api.maps.model.LatLng;
30 30
import com.amap.api.maps.model.MyLocationStyle;
31
import com.amap.api.services.core.AMapException;
31 32
import com.amap.api.services.core.LatLonPoint;
32 33
import com.amap.api.services.geocoder.GeocodeResult;
33 34
import com.amap.api.services.geocoder.GeocodeSearch;
@ -112,9 +113,14 @@ public class ShareMapActivity extends Activity implements View.OnClickListener,
112 113
            //获得地图的最大和最小缩放级别
113 114
            maxZoomLevel = aMap.getMaxZoomLevel();
114 115
            minZoomLevel = aMap.getMinZoomLevel();
115
            geocoderSearch = new GeocodeSearch(this);
116
            geocoderSearch.setOnGeocodeSearchListener(this);
117
            setUpMap();
116
            try {
117
                geocoderSearch = new GeocodeSearch(this);
118
                geocoderSearch.setOnGeocodeSearchListener(this);
119
                setUpMap();
120
            } catch (AMapException e) {
121
                e.printStackTrace();
122
            }
123
118 124
        }
119 125
    }
120 126
@ -399,24 +405,29 @@ public class ShareMapActivity extends Activity implements View.OnClickListener,
399 405
    public void activate(OnLocationChangedListener onLocationChangedListener) {
400 406
        mListener = onLocationChangedListener;
401 407
        if (mlocationClient == null) {
402
            mlocationClient = new AMapLocationClient(this);
403
            mLocationOption = new AMapLocationClientOption();
404
            //设置定位监听
405
            mlocationClient.setLocationListener(this);
406
            //设置为高精度定位模式
407
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
408
            //设置定位参数
409
            mlocationClient.setLocationOption(mLocationOption);
410
            // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
411
            // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
412
            // 在定位结束后,在合适的生命周期调用onDestroy()方法
413
            // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
414
            // 设置是否只定位一次,默认为false
415
            mLocationOption.setOnceLocation(true);
408
            try {
409
                mlocationClient = new AMapLocationClient(this);
410
                mLocationOption = new AMapLocationClientOption();
411
                //设置定位监听
412
                mlocationClient.setLocationListener(this);
413
                //设置为高精度定位模式
414
                mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
415
                //设置定位参数
416
                mlocationClient.setLocationOption(mLocationOption);
417
                // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
418
                // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
419
                // 在定位结束后,在合适的生命周期调用onDestroy()方法
420
                // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
421
                // 设置是否只定位一次,默认为false
422
                mLocationOption.setOnceLocation(true);
416 423
//            mLocationOption.setOnceLocationLatest(true);
417
            //设置是否强制刷新WIFI,默认为强制刷新
418
            mLocationOption.setWifiActiveScan(false);
419
            mlocationClient.startLocation();
424
                //设置是否强制刷新WIFI,默认为强制刷新
425
                mLocationOption.setWifiActiveScan(false);
426
                mlocationClient.startLocation();
427
            } catch (Exception e) {
428
                e.printStackTrace();
429
            }
430
420 431
421 432
        }
422 433
    }

+ 22 - 17
app/src/main/java/com/electric/chargingpile/activity/ShowBuildLocationActivity.java

@ -154,23 +154,28 @@ public class ShowBuildLocationActivity extends Activity implements AMap.OnCamera
154 154
    public void activate(OnLocationChangedListener onLocationChangedListener) {
155 155
        mListener = onLocationChangedListener;
156 156
        if (mlocationClient == null) {
157
            mlocationClient = new AMapLocationClient(this);
158
            mLocationOption = new AMapLocationClientOption();
159
            //设置定位监听
160
            mlocationClient.setLocationListener(this);
161
            //设置为高精度定位模式
162
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
163
            //设置定位参数
164
            mlocationClient.setLocationOption(mLocationOption);
165
            // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
166
            // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
167
            // 在定位结束后,在合适的生命周期调用onDestroy()方法
168
            // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
169
            // 设置是否只定位一次,默认为false
170
            mLocationOption.setOnceLocation(true);
171
            //设置是否强制刷新WIFI,默认为强制刷新
172
            mLocationOption.setWifiActiveScan(false);
173
            mlocationClient.startLocation();
157
            try {
158
                mlocationClient = new AMapLocationClient(this);
159
                mLocationOption = new AMapLocationClientOption();
160
                //设置定位监听
161
                mlocationClient.setLocationListener(this);
162
                //设置为高精度定位模式
163
                mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
164
                //设置定位参数
165
                mlocationClient.setLocationOption(mLocationOption);
166
                // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
167
                // 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
168
                // 在定位结束后,在合适的生命周期调用onDestroy()方法
169
                // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
170
                // 设置是否只定位一次,默认为false
171
                mLocationOption.setOnceLocation(true);
172
                //设置是否强制刷新WIFI,默认为强制刷新
173
                mLocationOption.setWifiActiveScan(false);
174
                mlocationClient.startLocation();
175
            } catch (Exception e) {
176
                e.printStackTrace();
177
            }
178
174 179
        }
175 180
    }
176 181

+ 18 - 9
app/src/main/java/com/electric/chargingpile/activity/SimpleNaviActivity.java

@ -8,6 +8,7 @@ import android.util.Log;
8 8
import android.view.Window;
9 9
import android.view.WindowManager;
10 10
11
import com.amap.api.maps.AMapException;
11 12
import com.amap.api.maps.model.BitmapDescriptor;
12 13
import com.amap.api.maps.model.BitmapDescriptorFactory;
13 14
import com.amap.api.navi.AMapNaviViewOptions;
@ -24,7 +25,7 @@ import com.amap.api.navi.model.AMapLaneInfo;
24 25
import com.amap.api.navi.model.AMapModelCross;
25 26
import com.amap.api.navi.model.AMapNaviCameraInfo;
26 27
import com.amap.api.navi.model.AMapNaviCross;
27
import com.amap.api.navi.model.AMapNaviInfo;
28
28 29
import com.amap.api.navi.model.AMapNaviLocation;
29 30
import com.amap.api.navi.model.AMapNaviPath;
30 31
import com.amap.api.navi.model.AMapNaviRouteNotifyData;
@ -33,7 +34,7 @@ import com.amap.api.navi.model.AMapServiceAreaInfo;
33 34
import com.amap.api.navi.model.AimLessModeCongestionInfo;
34 35
import com.amap.api.navi.model.AimLessModeStat;
35 36
import com.amap.api.navi.model.NaviInfo;
36
import com.autonavi.tbt.TrafficFacilityInfo;
37
37 38
import com.electric.chargingpile.R;
38 39
39 40
import java.util.List;
@ -73,7 +74,11 @@ public class SimpleNaviActivity extends Activity implements AMapNaviListener, AM
73 74
        options.setAfterRouteAutoGray(true);
74 75
        mAMapNaviView.setViewOptions(options);
75 76
76
        mAMapNavi = AMapNavi.getInstance(getApplicationContext());
77
        try {
78
            mAMapNavi = AMapNavi.getInstance(getApplicationContext());
79
        } catch (AMapException e) {
80
            e.printStackTrace();
81
        }
77 82
        mAMapNavi.addAMapNaviListener(this);
78 83
        mAMapNavi.setEmulatorNaviSpeed(60);
79 84
        mAMapNavi.setUseInnerVoice(true);
@ -189,9 +194,6 @@ public class SimpleNaviActivity extends Activity implements AMapNaviListener, AM
189 194
    public void onGpsOpenStatus(boolean b) {
190 195
    }
191 196
192
    @Override
193
    public void onNaviInfoUpdated(AMapNaviInfo aMapNaviInfo) {
194
    }
195 197
196 198
    @Override
197 199
    public void updateCameraInfo(AMapNaviCameraInfo[] aMapNaviCameraInfos) {
@ -215,9 +217,6 @@ public class SimpleNaviActivity extends Activity implements AMapNaviListener, AM
215 217
        }
216 218
    }
217 219
218
    @Override
219
    public void OnUpdateTrafficFacility(TrafficFacilityInfo trafficFacilityInfo) {
220
    }
221 220
222 221
    @Override
223 222
    public void OnUpdateTrafficFacility(AMapNaviTrafficFacilityInfo aMapNaviTrafficFacilityInfo) {
@ -302,6 +301,11 @@ public class SimpleNaviActivity extends Activity implements AMapNaviListener, AM
302 301
    }
303 302
304 303
    @Override
304
    public void onGpsSignalWeak(boolean b) {
305
306
    }
307
308
    @Override
305 309
    public void onNaviSetting() {
306 310
    }
307 311
@ -346,4 +350,9 @@ public class SimpleNaviActivity extends Activity implements AMapNaviListener, AM
346 350
    @Override
347 351
    public void onNaviViewShowMode(int i) {
348 352
    }
353
354
    @Override
355
    public void onPointerCaptureChanged(boolean hasCapture) {
356
357
    }
349 358
}

+ 15 - 10
app/src/main/java/com/electric/chargingpile/activity/SwitchCityActivity.java

@ -1310,27 +1310,32 @@ public class SwitchCityActivity extends Activity implements OnScrollListener, AM
1310 1310
    private void setUpMap() {
1311 1311
//        //声明mLocationOption对象
1312 1312
//        AMapLocationClientOption mLocationOption = null;
1313
        mlocationClient = new AMapLocationClient(this);
1314
//初始化定位参数
1315
        mLocationOption = new AMapLocationClientOption();
1313
        try {
1314
            mlocationClient = new AMapLocationClient(this);
1315
            //初始化定位参数
1316
            mLocationOption = new AMapLocationClientOption();
1316 1317
//设置定位监听
1317
        mlocationClient.setLocationListener(this);
1318
            mlocationClient.setLocationListener(this);
1318 1319
//设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
1319
        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
1320
        mLocationOption.setOnceLocation(true);
1321
        //设置是否强制刷新WIFI,默认为强制刷新
1322
        mLocationOption.setWifiActiveScan(false);
1320
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
1321
            mLocationOption.setOnceLocation(true);
1322
            //设置是否强制刷新WIFI,默认为强制刷新
1323
            mLocationOption.setWifiActiveScan(false);
1323 1324
//设置定位间隔,单位毫秒,默认为2000ms
1324 1325
//        mLocationOption.setInterval(2000);
1325 1326
//设置定位参数
1326
        mlocationClient.setLocationOption(mLocationOption);
1327
            mlocationClient.setLocationOption(mLocationOption);
1327 1328
// 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
1328 1329
// 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
1329 1330
// 在定位结束后,在合适的生命周期调用onDestroy()方法
1330 1331
// 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
1331 1332
1332 1333
//启动定位
1333
        mlocationClient.startLocation();
1334
            mlocationClient.startLocation();
1335
        } catch (Exception e) {
1336
            e.printStackTrace();
1337
        }
1338
1334 1339
    }
1335 1340
1336 1341
    @Override

+ 16 - 10
app/src/main/java/com/electric/chargingpile/activity/UserCenterActivity.java

@ -34,6 +34,7 @@ import android.widget.ToggleButton;
34 34
35 35
import androidx.annotation.NonNull;
36 36
37
import com.amap.api.services.core.AMapException;
37 38
import com.amap.api.services.weather.LocalDayWeatherForecast;
38 39
import com.amap.api.services.weather.LocalWeatherForecast;
39 40
import com.amap.api.services.weather.LocalWeatherForecastResult;
@ -293,16 +294,21 @@ public class UserCenterActivity extends Activity implements View.OnClickListener
293 294
        loadDialog = new LoadingDialog(this);
294 295
        loadDialog.setCanceledOnTouchOutside(false);
295 296
        mquery = new WeatherSearchQuery(MainMapActivity.location_city, WeatherSearchQuery.WEATHER_TYPE_FORECAST);
296
        mweathersearch = new WeatherSearch(this);
297
        mweathersearch.setOnWeatherSearchListener(this);
298
        mweathersearch.setQuery(mquery);
299
        mweathersearch.searchWeatherAsyn(); //异步搜索
300
301
        mquery1 = new WeatherSearchQuery(MainMapActivity.location_city, WeatherSearchQuery.WEATHER_TYPE_LIVE);
302
        mweathersearch1 = new WeatherSearch(this);
303
        mweathersearch1.setOnWeatherSearchListener(this);
304
        mweathersearch1.setQuery(mquery1);
305
        mweathersearch1.searchWeatherAsyn(); //异步搜索
297
        try {
298
            mweathersearch = new WeatherSearch(this);
299
            mweathersearch.setOnWeatherSearchListener(this);
300
            mweathersearch.setQuery(mquery);
301
            mweathersearch.searchWeatherAsyn(); //异步搜索
302
303
            mquery1 = new WeatherSearchQuery(MainMapActivity.location_city, WeatherSearchQuery.WEATHER_TYPE_LIVE);
304
            mweathersearch1 = new WeatherSearch(this);
305
            mweathersearch1.setOnWeatherSearchListener(this);
306
            mweathersearch1.setQuery(mquery1);
307
            mweathersearch1.searchWeatherAsyn(); //异步搜索
308
        } catch (AMapException e) {
309
            e.printStackTrace();
310
        }
311
306 312
        sv = (ObservableScrollView) findViewById(R.id.sv);
307 313
        sv.setScrollViewListener(this);
308 314
        iv_qiandao = (ImageView) findViewById(R.id.iv_qiandao);

+ 15 - 10
app/src/main/java/com/electric/chargingpile/adapter/CityListAdapter.java

@ -289,27 +289,32 @@ public class CityListAdapter extends BaseAdapter implements AMapLocationListener
289 289
    private void setUpMap() {
290 290
//        //声明mLocationOption对象
291 291
//        AMapLocationClientOption mLocationOption = null;
292
        mlocationClient = new AMapLocationClient(mActivity);
293
//初始化定位参数
294
        mLocationOption = new AMapLocationClientOption();
292
        try {
293
            mlocationClient = new AMapLocationClient(mActivity);
294
            //初始化定位参数
295
            mLocationOption = new AMapLocationClientOption();
295 296
//设置定位监听
296
        mlocationClient.setLocationListener(this);
297
            mlocationClient.setLocationListener(this);
297 298
//设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
298
        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
299
        mLocationOption.setOnceLocation(true);
300
        //设置是否强制刷新WIFI,默认为强制刷新
301
        mLocationOption.setWifiActiveScan(false);
299
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
300
            mLocationOption.setOnceLocation(true);
301
            //设置是否强制刷新WIFI,默认为强制刷新
302
            mLocationOption.setWifiActiveScan(false);
302 303
//设置定位间隔,单位毫秒,默认为2000ms
303 304
//        mLocationOption.setInterval(2000);
304 305
//设置定位参数
305
        mlocationClient.setLocationOption(mLocationOption);
306
            mlocationClient.setLocationOption(mLocationOption);
306 307
// 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
307 308
// 注意设置合适的定位时间的间隔(最小间隔支持为2000ms),并且在合适时间调用stopLocation()方法来取消定位请求
308 309
// 在定位结束后,在合适的生命周期调用onDestroy()方法
309 310
// 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
310 311
311 312
//启动定位
312
        mlocationClient.startLocation();
313
            mlocationClient.startLocation();
314
315
        } catch (Exception e) {
316
            e.printStackTrace();
317
        }
313 318
    }
314 319
315 320

+ 39 - 35
app/src/main/java/com/electric/chargingpile/adapter/ZhuangStatusadapter.java

@ -242,43 +242,47 @@ public class ZhuangStatusadapter extends BaseAdapter {
242 242
        final AMapLocationClient mlocationClient;
243 243
        //声明mLocationOption对象
244 244
        AMapLocationClientOption mLocationOption = null;
245
        mlocationClient = new AMapLocationClient(activity);
246
        //初始化定位参数
247
        mLocationOption = new AMapLocationClientOption();
248
        //设置定位监听
249
        mlocationClient.setLocationListener(new AMapLocationListener() {
250
            @Override
251
            public void onLocationChanged(AMapLocation amapLocation) {
252
                if (amapLocation != null) {
253
                    if (amapLocation.getErrorCode() == 0) {
254
                        //定位成功回调信息,设置相关消息
255
                        amapLocation.getLocationType();//获取当前定位结果来源,如网络定位结果,详见定位类型表
256
                        amapLocation.getLatitude();//获取纬度
257
                        amapLocation.getLongitude();//获取
258
                        amapLocation.getAccuracy();//获取精度信息
259
                        LogUtils.e(amapLocation.getLatitude() + "--" + amapLocation.getLongitude());
260
                        mlocationClient.stopLocation();
261
                        sendControlParkingDownLock(amapLocation, zhuangStatus);
262
                    } else {
263
                        //显示错误信息ErrCode是错误码,errInfo是错误信息,详见错误码表。
264
                        Log.e("AmapError", "location Error, ErrCode:"
265
                                + amapLocation.getErrorCode() + ", errInfo:"
266
                                + amapLocation.getErrorInfo());
245
        try {
246
            mlocationClient = new AMapLocationClient(activity);
247
            //初始化定位参数
248
            mLocationOption = new AMapLocationClientOption();
249
            //设置定位监听
250
            mlocationClient.setLocationListener(new AMapLocationListener() {
251
                @Override
252
                public void onLocationChanged(AMapLocation amapLocation) {
253
                    if (amapLocation != null) {
254
                        if (amapLocation.getErrorCode() == 0) {
255
                            //定位成功回调信息,设置相关消息
256
                            amapLocation.getLocationType();//获取当前定位结果来源,如网络定位结果,详见定位类型表
257
                            amapLocation.getLatitude();//获取
258
                            amapLocation.getLongitude();//获取经度
259
                            amapLocation.getAccuracy();//获取精度信息
260
                            LogUtils.e(amapLocation.getLatitude() + "--" + amapLocation.getLongitude());
261
                            mlocationClient.stopLocation();
262
                            sendControlParkingDownLock(amapLocation, zhuangStatus);
263
                        } else {
264
                            //显示错误信息ErrCode是错误码,errInfo是错误信息,详见错误码表。
265
                            Log.e("AmapError", "location Error, ErrCode:"
266
                                    + amapLocation.getErrorCode() + ", errInfo:"
267
                                    + amapLocation.getErrorInfo());
268
                        }
267 269
                    }
268 270
                }
269
            }
270
        });
271
        //设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
272
        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
273
        //设置定位间隔,单位毫秒,默认为2000ms//        mLocationOption.setInterval(2000);
274
        //设置定位参数
275
        mlocationClient.setLocationOption(mLocationOption);
276
        // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
277
        // 注意设置合适的定位时间的间隔(最小间隔支持为1000ms),并且在合适时间调用stopLocation()方法来取消定位请求
278
        // 在定位结束后,在合适的生命周期调用onDestroy()方法
279
        // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
280
        //启动定位
281
        mlocationClient.startLocation();
271
            });
272
            //设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
273
            mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
274
            //设置定位间隔,单位毫秒,默认为2000ms//        mLocationOption.setInterval(2000);
275
            //设置定位参数
276
            mlocationClient.setLocationOption(mLocationOption);
277
            // 此方法为每隔固定时间会发起一次定位请求,为了减少电量消耗或网络流量消耗,
278
            // 注意设置合适的定位时间的间隔(最小间隔支持为1000ms),并且在合适时间调用stopLocation()方法来取消定位请求
279
            // 在定位结束后,在合适的生命周期调用onDestroy()方法
280
            // 在单次定位情况下,定位无论成功与否,都无需调用stopLocation()方法移除请求,定位sdk内部会移除
281
            //启动定位
282
            mlocationClient.startLocation();
283
        } catch (Exception e) {
284
            e.printStackTrace();
285
        }
282 286
    }
283 287
284 288
    private void sendControlParkingDownLock(AMapLocation amapLocation, ZhuangStatus zhuangStatus) {

+ 6 - 0
app/src/main/java/com/electric/chargingpile/application/MainApplication.java

@ -13,6 +13,7 @@ import android.util.Log;
13 13
import androidx.multidex.MultiDexApplication;
14 14

15 15
import com.alibaba.fastjson.JSONException;
16
import com.amap.api.location.AMapLocationClient;
16 17
import com.amap.api.maps.model.LatLng;
17 18
import com.blankj.utilcode.util.LogUtils;
18 19
import com.blankj.utilcode.util.Utils;
@ -199,6 +200,9 @@ public class MainApplication extends MultiDexApplication {
199 200
        userCarIntentMode = ProfileManager.getInstance().getCarIntentModel(getApplicationContext());
200 201
        loginRemind();
201 202
        setFestival();
203
        if (ProfileManager.getInstance().getPrivacyAgreement(this)) {
204
            MainApplication.initSDK();
205
        }
202 206
    }
203 207

204 208
    public void initJPush() {
@ -392,6 +396,8 @@ public class MainApplication extends MultiDexApplication {
392 396
    }
393 397

394 398
    public static void initSDK() {
399
        AMapLocationClient.updatePrivacyShow(context,true,true);
400
        AMapLocationClient.updatePrivacyAgree(context,true);
395 401
        MobSDK.init(MainApplication.context);
396 402
        MobSDK.submitPolicyGrantResult(true,null);
397 403
        CrashReport.initCrashReport(MainApplication.context, "900010422", BuildConfig.DEBUG);

+ 7 - 9
app/src/main/java/com/electric/chargingpile/util/TTSController.java

@ -10,7 +10,7 @@ import com.amap.api.navi.model.AMapLaneInfo;
10 10
import com.amap.api.navi.model.AMapModelCross;
11 11
import com.amap.api.navi.model.AMapNaviCameraInfo;
12 12
import com.amap.api.navi.model.AMapNaviCross;
13
import com.amap.api.navi.model.AMapNaviInfo;
13
14 14
import com.amap.api.navi.model.AMapNaviLocation;
15 15
import com.amap.api.navi.model.AMapNaviRouteNotifyData;
16 16
import com.amap.api.navi.model.AMapNaviTrafficFacilityInfo;
@ -18,7 +18,7 @@ import com.amap.api.navi.model.AMapServiceAreaInfo;
18 18
import com.amap.api.navi.model.AimLessModeCongestionInfo;
19 19
import com.amap.api.navi.model.AimLessModeStat;
20 20
import com.amap.api.navi.model.NaviInfo;
21
import com.autonavi.tbt.TrafficFacilityInfo;
21
22 22
import com.blankj.utilcode.util.LogUtils;
23 23
import com.electric.chargingpile.R;
24 24
import com.iflytek.cloud.speech.SpeechConstant;
@ -279,11 +279,7 @@ public class TTSController implements SynthesizerListener, AMapNaviListener, AMa
279 279
280 280
    }
281 281
282
    @Override
283
    public void onNaviInfoUpdated(AMapNaviInfo arg0) {
284
        // TODO Auto-generated method stub
285 282
286
    }
287 283
288 284
    @Override
289 285
    public void updateCameraInfo(AMapNaviCameraInfo[] aMapNaviCameraInfos) {
@ -307,10 +303,7 @@ public class TTSController implements SynthesizerListener, AMapNaviListener, AMa
307 303
308 304
    }
309 305
310
    @Override
311
    public void OnUpdateTrafficFacility(TrafficFacilityInfo trafficFacilityInfo) {
312 306
313
    }
314 307
315 308
    @Override
316 309
    public void OnUpdateTrafficFacility(AMapNaviTrafficFacilityInfo aMapNaviTrafficFacilityInfo) {
@ -401,6 +394,11 @@ public class TTSController implements SynthesizerListener, AMapNaviListener, AMa
401 394
    }
402 395
403 396
    @Override
397
    public void onGpsSignalWeak(boolean b) {
398
399
    }
400
401
    @Override
404 402
    public void onNaviSetting() {
405 403
    }
406 404

BIN
app/src/main/jniLibs/arm64-v8a/libAMapSDK_MAP_v6_9_2.so


BIN
app/src/main/jniLibs/arm64-v8a/libAMapSDK_NAVI_v6_9_0.so


BIN
app/src/main/jniLibs/arm64-v8a/libAMapSDK_NAVI_v8_1_0.so


BIN
app/src/main/jniLibs/arm64-v8a/libneonui_shared.so


BIN
app/src/main/jniLibs/arm64-v8a/libneonuijni_public.so


BIN
app/src/main/jniLibs/armeabi-v7a/libAMapSDK_MAP_v6_9_2.so


BIN
app/src/main/jniLibs/armeabi-v7a/libAMapSDK_NAVI_v6_9_0.so


BIN
app/src/main/jniLibs/armeabi-v7a/libAMapSDK_NAVI_v8_1_0.so


BIN
app/src/main/jniLibs/armeabi-v7a/libneonui_shared.so


BIN
app/src/main/jniLibs/armeabi-v7a/libneonuijni_public.so


BIN
app/src/main/jniLibs/armeabi/libAMapSDK_MAP_v6_9_2.so


BIN
app/src/main/jniLibs/armeabi/libAMapSDK_NAVI_v6_9_0.so


BIN
app/src/main/jniLibs/armeabi/libAMapSDK_NAVI_v8_1_0.so


BIN
app/src/main/jniLibs/armeabi/libneonui_shared.so


BIN
app/src/main/jniLibs/armeabi/libneonuijni_public.so


add richtext · 63487e0a25 - Gogs: Go Git Service
浏览代码

add richtext

1145873331@qq.com 7 年之前
父节点
当前提交
63487e0a25

+ 46 - 0
app/src/main/java/com/electric/chargingpile/view/xrichtext/DataImageView.java

@ -0,0 +1,46 @@
1
package com.electric.chargingpile.view.xrichtext;
2
3
import android.content.Context;
4
import android.graphics.Bitmap;
5
import android.util.AttributeSet;
6
import android.widget.ImageView;
7
8
/**
9
 * 这只是一个简单的ImageView,可以存放Bitmap和Path等信息
10
 *
11
 * @author xmuSistone
12
 */
13
public class DataImageView extends ImageView {
14
15
    private String absolutePath;
16
    private Bitmap bitmap;
17
18
    public DataImageView(Context context) {
19
        this(context, null);
20
    }
21
22
    public DataImageView(Context context, AttributeSet attrs) {
23
        this(context, attrs, 0);
24
    }
25
26
    public DataImageView(Context context, AttributeSet attrs, int defStyle) {
27
        super(context, attrs, defStyle);
28
    }
29
30
    public String getAbsolutePath() {
31
        return absolutePath;
32
    }
33
34
    public void setAbsolutePath(String absolutePath) {
35
        this.absolutePath = absolutePath;
36
    }
37
38
    public Bitmap getBitmap() {
39
        return bitmap;
40
    }
41
42
    public void setBitmap(Bitmap bitmap) {
43
        this.bitmap = bitmap;
44
    }
45
46
}

+ 60 - 0
app/src/main/java/com/electric/chargingpile/view/xrichtext/DeletableEditText.java

@ -0,0 +1,60 @@
1
package com.electric.chargingpile.view.xrichtext;
2
3
import android.content.Context;
4
import android.util.AttributeSet;
5
import android.view.KeyEvent;
6
import android.view.inputmethod.EditorInfo;
7
import android.view.inputmethod.InputConnection;
8
import android.view.inputmethod.InputConnectionWrapper;
9
import android.widget.EditText;
10
11
/**
12
 * 这个是从stackOverFlow上面找到的解决方案,主要用途是处理软键盘回删按钮backSpace时回调OnKeyListener
13
 *
14
 * @author xmuSistone
15
 */
16
public class DeletableEditText extends EditText {
17
18
    public DeletableEditText(Context context, AttributeSet attrs, int defStyle) {
19
        super(context, attrs, defStyle);
20
    }
21
22
    public DeletableEditText(Context context, AttributeSet attrs) {
23
        super(context, attrs);
24
    }
25
26
    public DeletableEditText(Context context) {
27
        super(context);
28
    }
29
30
    @Override
31
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
32
        return new DeleteInputConnection(super.onCreateInputConnection(outAttrs),
33
                true);
34
    }
35
36
    private class DeleteInputConnection extends InputConnectionWrapper {
37
38
        public DeleteInputConnection(InputConnection target, boolean mutable) {
39
            super(target, mutable);
40
        }
41
42
        @Override
43
        public boolean sendKeyEvent(KeyEvent event) {
44
            return super.sendKeyEvent(event);
45
        }
46
47
        @Override
48
        public boolean deleteSurroundingText(int beforeLength, int afterLength) {
49
            if (beforeLength == 1 && afterLength == 0) {
50
                return sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN,
51
                        KeyEvent.KEYCODE_DEL))
52
                        && sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP,
53
                        KeyEvent.KEYCODE_DEL));
54
            }
55
56
            return super.deleteSurroundingText(beforeLength, afterLength);
57
        }
58
59
    }
60
}

+ 1546 - 0
app/src/main/java/com/electric/chargingpile/view/xrichtext/ImageUtils.java

@ -0,0 +1,1546 @@
1
package com.electric.chargingpile.view.xrichtext;
2
3
import android.graphics.Bitmap;
4
import android.graphics.Bitmap.CompressFormat;
5
import android.graphics.BitmapFactory;
6
import android.graphics.Canvas;
7
import android.graphics.Color;
8
import android.graphics.ColorMatrix;
9
import android.graphics.ColorMatrixColorFilter;
10
import android.graphics.LinearGradient;
11
import android.graphics.Matrix;
12
import android.graphics.Paint;
13
import android.graphics.PixelFormat;
14
import android.graphics.PorterDuff;
15
import android.graphics.PorterDuffXfermode;
16
import android.graphics.Rect;
17
import android.graphics.RectF;
18
import android.graphics.Shader;
19
import android.graphics.drawable.BitmapDrawable;
20
import android.graphics.drawable.Drawable;
21
import android.media.ExifInterface;
22
import android.support.annotation.IntRange;
23
import android.view.View;
24
25
import java.io.ByteArrayOutputStream;
26
import java.io.File;
27
import java.io.FileDescriptor;
28
import java.io.IOException;
29
import java.io.InputStream;
30
31
/**
32
 * Created by demon on 2017/8/30.
33
 */
34
35
public class ImageUtils {
36
    private ImageUtils() {
37
        throw new UnsupportedOperationException("u can't instantiate me...");
38
    }
39
40
    /**
41
     * bitmap转byteArr
42
     *
43
     * @param bitmap bitmap对象
44
     * @param format 格式
45
     * @return 字节数组
46
     */
47
    public static byte[] bitmap2Bytes(final Bitmap bitmap, final CompressFormat format) {
48
        if (bitmap == null) return null;
49
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
50
        bitmap.compress(format, 100, baos);
51
        return baos.toByteArray();
52
    }
53
54
    /**
55
     * byteArr转bitmap
56
     *
57
     * @param bytes 字节数组
58
     * @return bitmap
59
     */
60
    public static Bitmap bytes2Bitmap(final byte[] bytes) {
61
        return (bytes == null || bytes.length == 0) ? null : BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
62
    }
63
64
    /**
65
     * drawable转bitmap
66
     *
67
     * @param drawable drawable对象
68
     * @return bitmap
69
     */
70
    public static Bitmap drawable2Bitmap(final Drawable drawable) {
71
        if (drawable instanceof BitmapDrawable) {
72
            BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
73
            if (bitmapDrawable.getBitmap() != null) {
74
                return bitmapDrawable.getBitmap();
75
            }
76
        }
77
        Bitmap bitmap;
78
        if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
79
            bitmap = Bitmap.createBitmap(1, 1,
80
                    drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
81
        } else {
82
            bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
83
                    drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
84
        }
85
        Canvas canvas = new Canvas(bitmap);
86
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
87
        drawable.draw(canvas);
88
        return bitmap;
89
    }
90
91
    /**
92
     * bitmap转drawable
93
     *
94
     * @param bitmap bitmap对象
95
     * @return drawable
96
     */
97
//    public static Drawable bitmap2Drawable(final Bitmap bitmap) {
98
//        return bitmap == null ? null : new BitmapDrawable(Utils.getApp().getResources(), bitmap);
99
//    }
100
101
    /**
102
     * drawable转byteArr
103
     *
104
     * @param drawable drawable对象
105
     * @param format   格式
106
     * @return 字节数组
107
     */
108
    public static byte[] drawable2Bytes(final Drawable drawable, final CompressFormat format) {
109
        return drawable == null ? null : bitmap2Bytes(drawable2Bitmap(drawable), format);
110
    }
111
112
    /**
113
     * byteArr转drawable
114
     *
115
     * @param bytes 字节数组
116
     * @return drawable
117
     */
118
//    public static Drawable bytes2Drawable(final byte[] bytes) {
119
//        return bitmap2Drawable(bytes2Bitmap(bytes));
120
//    }
121
122
    /**
123
     * view转Bitmap
124
     *
125
     * @param view 视图
126
     * @return bitmap
127
     */
128
    public static Bitmap view2Bitmap(final View view) {
129
        if (view == null) return null;
130
        Bitmap ret = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
131
        Canvas canvas = new Canvas(ret);
132
        Drawable bgDrawable = view.getBackground();
133
        if (bgDrawable != null) {
134
            bgDrawable.draw(canvas);
135
        } else {
136
            canvas.drawColor(Color.WHITE);
137
        }
138
        view.draw(canvas);
139
        return ret;
140
    }
141
142
    /**
143
     * 计算采样大小
144
     *
145
     * @param options   选项
146
     * @param maxWidth  最大宽度
147
     * @param maxHeight 最大高度
148
     * @return 采样大小
149
     */
150
    private static int calculateInSampleSize(final BitmapFactory.Options options, final int maxWidth, final int maxHeight) {
151
        if (maxWidth == 0 || maxHeight == 0) return 1;
152
        int height = options.outHeight;
153
        int width = options.outWidth;
154
        int inSampleSize = 1;
155
        while ((height >>= 1) > maxHeight && (width >>= 1) > maxWidth) {
156
            inSampleSize <<= 1;
157
        }
158
        return inSampleSize;
159
    }
160
161
    /**
162
     * 获取bitmap
163
     *
164
     * @param file 文件
165
     * @return bitmap
166
     */
167
//    public static Bitmap getBitmap(final File file) {
168
//        if (file == null) return null;
169
//        InputStream is = null;
170
//        try {
171
//            is = new BufferedInputStream(new FileInputStream(file));
172
//            return BitmapFactory.decodeStream(is);
173
//        } catch (FileNotFoundException e) {
174
//            e.printStackTrace();
175
//            return null;
176
//        } finally {
177
//            CloseUtils.closeIO(is);
178
//        }
179
//    }
180
181
    /**
182
     * 获取bitmap
183
     *
184
     * @param file      文件
185
     * @param maxWidth  最大宽度
186
     * @param maxHeight 最大高度
187
     * @return bitmap
188
     */
189
//    public static Bitmap getBitmap(final File file, final int maxWidth, final int maxHeight) {
190
//        if (file == null) return null;
191
//        InputStream is = null;
192
//        try {
193
//            BitmapFactory.Options options = new BitmapFactory.Options();
194
//            options.inJustDecodeBounds = true;
195
//            is = new BufferedInputStream(new FileInputStream(file));
196
//            BitmapFactory.decodeStream(is, null, options);
197
//            options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
198
//            options.inJustDecodeBounds = false;
199
//            return BitmapFactory.decodeStream(is, null, options);
200
//        } catch (FileNotFoundException e) {
201
//            e.printStackTrace();
202
//            return null;
203
//        } finally {
204
//            CloseUtils.closeIO(is);
205
//        }
206
//    }
207
208
    /**
209
     * 获取bitmap
210
     *
211
     * @param filePath 文件路径
212
     * @return bitmap
213
     */
214
    public static Bitmap getBitmap(final String filePath) {
215
        if (isSpace(filePath)) return null;
216
        return BitmapFactory.decodeFile(filePath);
217
    }
218
219
    /**
220
     * 获取bitmap
221
     *
222
     * @param filePath  文件路径
223
     * @param maxWidth  最大宽度
224
     * @param maxHeight 最大高度
225
     * @return bitmap
226
     */
227
    public static Bitmap getBitmap(final String filePath, final int maxWidth, final int maxHeight) {
228
        if (isSpace(filePath)) return null;
229
        BitmapFactory.Options options = new BitmapFactory.Options();
230
        options.inJustDecodeBounds = true;
231
        BitmapFactory.decodeFile(filePath, options);
232
        options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
233
        options.inJustDecodeBounds = false;
234
        return BitmapFactory.decodeFile(filePath, options);
235
    }
236
237
    /**
238
     * 获取bitmap
239
     *
240
     * @param is 输入流
241
     * @return bitmap
242
     */
243
    public static Bitmap getBitmap(final InputStream is) {
244
        if (is == null) return null;
245
        return BitmapFactory.decodeStream(is);
246
    }
247
248
    /**
249
     * 获取bitmap
250
     *
251
     * @param is        输入流
252
     * @param maxWidth  最大宽度
253
     * @param maxHeight 最大高度
254
     * @return bitmap
255
     */
256
    public static Bitmap getBitmap(final InputStream is, final int maxWidth, final int maxHeight) {
257
        if (is == null) return null;
258
        BitmapFactory.Options options = new BitmapFactory.Options();
259
        options.inJustDecodeBounds = true;
260
        BitmapFactory.decodeStream(is, null, options);
261
        options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
262
        options.inJustDecodeBounds = false;
263
        return BitmapFactory.decodeStream(is, null, options);
264
    }
265
266
    /**
267
     * 获取bitmap
268
     *
269
     * @param data   数据
270
     * @param offset 偏移量
271
     * @return bitmap
272
     */
273
    public static Bitmap getBitmap(final byte[] data, final int offset) {
274
        if (data.length == 0) return null;
275
        return BitmapFactory.decodeByteArray(data, offset, data.length);
276
    }
277
278
    /**
279
     * 获取bitmap
280
     *
281
     * @param data      数据
282
     * @param offset    偏移量
283
     * @param maxWidth  最大宽度
284
     * @param maxHeight 最大高度
285
     * @return bitmap
286
     */
287
    public static Bitmap getBitmap(final byte[] data, final int offset, final int maxWidth, final int maxHeight) {
288
        if (data.length == 0) return null;
289
        BitmapFactory.Options options = new BitmapFactory.Options();
290
        options.inJustDecodeBounds = true;
291
        BitmapFactory.decodeByteArray(data, offset, data.length, options);
292
        options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
293
        options.inJustDecodeBounds = false;
294
        return BitmapFactory.decodeByteArray(data, offset, data.length, options);
295
    }
296
297
    /**
298
     * 获取bitmap
299
     *
300
     * @param resId 资源id
301
     * @return bitmap
302
     */
303
//    public static Bitmap getBitmap(@DrawableRes final int resId) {
304
//        return BitmapFactory.decodeResource(Utils.getApp().getResources(), resId);
305
//    }
306
307
    /**
308
     * 获取bitmap
309
     *
310
     * @param resId     资源id
311
     * @param maxWidth  最大宽度
312
     * @param maxHeight 最大高度
313
     * @return bitmap
314
     */
315
//    public static Bitmap getBitmap(@DrawableRes final int resId, final int maxWidth, final int maxHeight) {
316
//        BitmapFactory.Options options = new BitmapFactory.Options();
317
//        options.inJustDecodeBounds = true;
318
//        BitmapFactory.decodeResource(Utils.getApp().getResources(), resId, options);
319
//        options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
320
//        options.inJustDecodeBounds = false;
321
//        return BitmapFactory.decodeResource(Utils.getApp().getResources(), resId, options);
322
//    }
323
324
    /**
325
     * 获取bitmap
326
     *
327
     * @param fd 文件描述
328
     * @return bitmap
329
     */
330
    public static Bitmap getBitmap(final FileDescriptor fd) {
331
        if (fd == null) return null;
332
        return BitmapFactory.decodeFileDescriptor(fd);
333
    }
334
335
    /**
336
     * 获取bitmap
337
     *
338
     * @param fd        文件描述
339
     * @param maxWidth  最大宽度
340
     * @param maxHeight 最大高度
341
     * @return bitmap
342
     */
343
    public static Bitmap getBitmap(final FileDescriptor fd, final int maxWidth, final int maxHeight) {
344
        if (fd == null) return null;
345
        BitmapFactory.Options options = new BitmapFactory.Options();
346
        options.inJustDecodeBounds = true;
347
        BitmapFactory.decodeFileDescriptor(fd, null, options);
348
        options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);
349
        options.inJustDecodeBounds = false;
350
        return BitmapFactory.decodeFileDescriptor(fd, null, options);
351
    }
352
353
    /**
354
     * 缩放图片
355
     *
356
     * @param src       源图片
357
     * @param newWidth  新宽度
358
     * @param newHeight 新高度
359
     * @return 缩放后的图片
360
     */
361
    public static Bitmap scale(final Bitmap src, final int newWidth, final int newHeight) {
362
        return scale(src, newWidth, newHeight, false);
363
    }
364
365
    /**
366
     * 缩放图片
367
     *
368
     * @param src       源图片
369
     * @param newWidth  新宽度
370
     * @param newHeight 新高度
371
     * @param recycle   是否回收
372
     * @return 缩放后的图片
373
     */
374
    public static Bitmap scale(final Bitmap src, final int newWidth, final int newHeight, final boolean recycle) {
375
        if (isEmptyBitmap(src)) return null;
376
        Bitmap ret = Bitmap.createScaledBitmap(src, newWidth, newHeight, true);
377
        if (recycle && !src.isRecycled()) src.recycle();
378
        return ret;
379
    }
380
381
    /**
382
     * 缩放图片
383
     *
384
     * @param src         源图片
385
     * @param scaleWidth  缩放宽度倍数
386
     * @param scaleHeight 缩放高度倍数
387
     * @return 缩放后的图片
388
     */
389
    public static Bitmap scale(final Bitmap src, final float scaleWidth, final float scaleHeight) {
390
        return scale(src, scaleWidth, scaleHeight, false);
391
    }
392
393
    /**
394
     * 缩放图片
395
     *
396
     * @param src         源图片
397
     * @param scaleWidth  缩放宽度倍数
398
     * @param scaleHeight 缩放高度倍数
399
     * @param recycle     是否回收
400
     * @return 缩放后的图片
401
     */
402
    public static Bitmap scale(final Bitmap src, final float scaleWidth, final float scaleHeight, final boolean recycle) {
403
        if (isEmptyBitmap(src)) return null;
404
        Matrix matrix = new Matrix();
405
        matrix.setScale(scaleWidth, scaleHeight);
406
        Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
407
        if (recycle && !src.isRecycled()) src.recycle();
408
        return ret;
409
    }
410
411
    /**
412
     * 裁剪图片
413
     *
414
     * @param src    源图片
415
     * @param x      开始坐标x
416
     * @param y      开始坐标y
417
     * @param width  裁剪宽度
418
     * @param height 裁剪高度
419
     * @return 裁剪后的图片
420
     */
421
    public static Bitmap clip(final Bitmap src, final int x, final int y, final int width, final int height) {
422
        return clip(src, x, y, width, height, false);
423
    }
424
425
    /**
426
     * 裁剪图片
427
     *
428
     * @param src     源图片
429
     * @param x       开始坐标x
430
     * @param y       开始坐标y
431
     * @param width   裁剪宽度
432
     * @param height  裁剪高度
433
     * @param recycle 是否回收
434
     * @return 裁剪后的图片
435
     */
436
    public static Bitmap clip(final Bitmap src, final int x, final int y, final int width, final int height, final boolean recycle) {
437
        if (isEmptyBitmap(src)) return null;
438
        Bitmap ret = Bitmap.createBitmap(src, x, y, width, height);
439
        if (recycle && !src.isRecycled()) src.recycle();
440
        return ret;
441
    }
442
443
    /**
444
     * 倾斜图片
445
     *
446
     * @param src 源图片
447
     * @param kx  倾斜因子x
448
     * @param ky  倾斜因子y
449
     * @return 倾斜后的图片
450
     */
451
    public static Bitmap skew(final Bitmap src, final float kx, final float ky) {
452
        return skew(src, kx, ky, 0, 0, false);
453
    }
454
455
    /**
456
     * 倾斜图片
457
     *
458
     * @param src     源图片
459
     * @param kx      倾斜因子x
460
     * @param ky      倾斜因子y
461
     * @param recycle 是否回收
462
     * @return 倾斜后的图片
463
     */
464
    public static Bitmap skew(final Bitmap src, final float kx, final float ky, final boolean recycle) {
465
        return skew(src, kx, ky, 0, 0, recycle);
466
    }
467
468
    /**
469
     * 倾斜图片
470
     *
471
     * @param src 源图片
472
     * @param kx  倾斜因子x
473
     * @param ky  倾斜因子y
474
     * @param px  平移因子x
475
     * @param py  平移因子y
476
     * @return 倾斜后的图片
477
     */
478
    public static Bitmap skew(final Bitmap src, final float kx, final float ky, final float px, final float py) {
479
        return skew(src, kx, ky, px, py, false);
480
    }
481
482
    /**
483
     * 倾斜图片
484
     *
485
     * @param src     源图片
486
     * @param kx      倾斜因子x
487
     * @param ky      倾斜因子y
488
     * @param px      平移因子x
489
     * @param py      平移因子y
490
     * @param recycle 是否回收
491
     * @return 倾斜后的图片
492
     */
493
    public static Bitmap skew(final Bitmap src, final float kx, final float ky, final float px, final float py, final boolean recycle) {
494
        if (isEmptyBitmap(src)) return null;
495
        Matrix matrix = new Matrix();
496
        matrix.setSkew(kx, ky, px, py);
497
        Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
498
        if (recycle && !src.isRecycled()) src.recycle();
499
        return ret;
500
    }
501
502
    /**
503
     * 旋转图片
504
     *
505
     * @param src     源图片
506
     * @param degrees 旋转角度
507
     * @param px      旋转点横坐标
508
     * @param py      旋转点纵坐标
509
     * @return 旋转后的图片
510
     */
511
    public static Bitmap rotate(final Bitmap src, final int degrees, final float px, final float py) {
512
        return rotate(src, degrees, px, py, false);
513
    }
514
515
    /**
516
     * 旋转图片
517
     *
518
     * @param src     源图片
519
     * @param degrees 旋转角度
520
     * @param px      旋转点横坐标
521
     * @param py      旋转点纵坐标
522
     * @param recycle 是否回收
523
     * @return 旋转后的图片
524
     */
525
    public static Bitmap rotate(final Bitmap src, final int degrees, final float px, final float py, final boolean recycle) {
526
        if (isEmptyBitmap(src)) return null;
527
        if (degrees == 0) return src;
528
        Matrix matrix = new Matrix();
529
        matrix.setRotate(degrees, px, py);
530
        Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
531
        if (recycle && !src.isRecycled()) src.recycle();
532
        return ret;
533
    }
534
535
    /**
536
     * 获取图片旋转角度
537
     *
538
     * @param filePath 文件路径
539
     * @return 旋转角度
540
     */
541
    public static int getRotateDegree(final String filePath) {
542
        int degree = 0;
543
        try {
544
            ExifInterface exifInterface = new ExifInterface(filePath);
545
            int orientation = exifInterface.getAttributeInt(
546
                    ExifInterface.TAG_ORIENTATION,
547
                    ExifInterface.ORIENTATION_NORMAL);
548
            switch (orientation) {
549
                default:
550
                case ExifInterface.ORIENTATION_ROTATE_90:
551
                    degree = 90;
552
                    break;
553
                case ExifInterface.ORIENTATION_ROTATE_180:
554
                    degree = 180;
555
                    break;
556
                case ExifInterface.ORIENTATION_ROTATE_270:
557
                    degree = 270;
558
                    break;
559
            }
560
        } catch (IOException e) {
561
            e.printStackTrace();
562
        }
563
        return degree;
564
    }
565
566
    /**
567
     * 转为圆形图片
568
     *
569
     * @param src 源图片
570
     * @return 圆形图片
571
     */
572
    public static Bitmap toRound(final Bitmap src) {
573
        return toRound(src, false);
574
    }
575
576
    /**
577
     * 转为圆形图片
578
     *
579
     * @param src     源图片
580
     * @param recycle 是否回收
581
     * @return 圆形图片
582
     */
583
    public static Bitmap toRound(final Bitmap src, final boolean recycle) {
584
        if (isEmptyBitmap(src)) return null;
585
        int width = src.getWidth();
586
        int height = src.getHeight();
587
        int radius = Math.min(width, height) >> 1;
588
        Bitmap ret = Bitmap.createBitmap(width, height, src.getConfig());
589
        Paint paint = new Paint();
590
        Canvas canvas = new Canvas(ret);
591
        Rect rect = new Rect(0, 0, width, height);
592
        paint.setAntiAlias(true);
593
        canvas.drawARGB(0, 0, 0, 0);
594
        canvas.drawCircle(width >> 1, height >> 1, radius, paint);
595
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
596
        canvas.drawBitmap(src, rect, rect, paint);
597
        if (recycle && !src.isRecycled()) src.recycle();
598
        return ret;
599
    }
600
601
    /**
602
     * 转为圆角图片
603
     *
604
     * @param src    源图片
605
     * @param radius 圆角的度数
606
     * @return 圆角图片
607
     */
608
    public static Bitmap toRoundCorner(final Bitmap src, final float radius) {
609
        return toRoundCorner(src, radius, false);
610
    }
611
612
    /**
613
     * 转为圆角图片
614
     *
615
     * @param src     源图片
616
     * @param radius  圆角的度数
617
     * @param recycle 是否回收
618
     * @return 圆角图片
619
     */
620
    public static Bitmap toRoundCorner(final Bitmap src, final float radius, final boolean recycle) {
621
        if (null == src) return null;
622
        int width = src.getWidth();
623
        int height = src.getHeight();
624
        Bitmap ret = Bitmap.createBitmap(width, height, src.getConfig());
625
        Paint paint = new Paint();
626
        Canvas canvas = new Canvas(ret);
627
        Rect rect = new Rect(0, 0, width, height);
628
        paint.setAntiAlias(true);
629
        canvas.drawRoundRect(new RectF(rect), radius, radius, paint);
630
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
631
        canvas.drawBitmap(src, rect, rect, paint);
632
        if (recycle && !src.isRecycled()) src.recycle();
633
        return ret;
634
    }
635
636
    /**
637
     * 快速模糊
638
     * <p>先缩小原图,对小图进行模糊,再放大回原先尺寸</p>
639
     *
640
     * @param src    源图片
641
     * @param scale  缩放比例(0...1)
642
     * @param radius 模糊半径
643
     * @return 模糊后的图片
644
     */
645
//    public static Bitmap fastBlur(final Bitmap src,
646
//                                  @FloatRange(from = 0, to = 1, fromInclusive = false) final float scale,
647
//                                  @FloatRange(from = 0, to = 25, fromInclusive = false) final float radius) {
648
//        return fastBlur(src, scale, radius, false);
649
//    }
650
651
    /**
652
     * 快速模糊图片
653
     * <p>先缩小原图,对小图进行模糊,再放大回原先尺寸</p>
654
     *
655
     * @param src     源图片
656
     * @param scale   缩放比例(0...1)
657
     * @param radius  模糊半径(0...25)
658
     * @param recycle 是否回收
659
     * @return 模糊后的图片
660
     */
661
//    public static Bitmap fastBlur(final Bitmap src,
662
//                                  @FloatRange(from = 0, to = 1, fromInclusive = false) final float scale,
663
//                                  @FloatRange(from = 0, to = 25, fromInclusive = false) final float radius,
664
//                                  boolean recycle) {
665
//        if (isEmptyBitmap(src)) return null;
666
//        int width = src.getWidth();
667
//        int height = src.getHeight();
668
//        int scaleWidth = (int) (width * scale + 0.5f);
669
//        int scaleHeight = (int) (height * scale + 0.5f);
670
//        if (scaleWidth == 0 || scaleHeight == 0) return null;
671
//        Bitmap scaleBitmap = Bitmap.createScaledBitmap(src, scaleWidth, scaleHeight, true);
672
//        Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
673
//        Canvas canvas = new Canvas();
674
//        PorterDuffColorFilter filter = new PorterDuffColorFilter(
675
//                Color.TRANSPARENT, PorterDuff.Mode.SRC_ATOP);
676
//        paint.setColorFilter(filter);
677
//        canvas.scale(scale, scale);
678
//        canvas.drawBitmap(scaleBitmap, 0, 0, paint);
679
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
680
//            scaleBitmap = renderScriptBlur(scaleBitmap, radius);
681
//        } else {
682
//            scaleBitmap = stackBlur(scaleBitmap, (int) radius, recycle);
683
//        }
684
//        if (scale == 1) return scaleBitmap;
685
//        Bitmap ret = Bitmap.createScaledBitmap(scaleBitmap, width, height, true);
686
//        if (scaleBitmap != null && !scaleBitmap.isRecycled()) scaleBitmap.recycle();
687
//        if (recycle && !src.isRecycled()) src.recycle();
688
//        return ret;
689
//    }
690
691
    /**
692
     * renderScript模糊图片
693
     * <p>API大于17</p>
694
     *
695
     * @param src    源图片
696
     * @param radius 模糊半径(0...25)
697
     * @return 模糊后的图片
698
     */
699
//    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
700
//    public static Bitmap renderScriptBlur(final Bitmap src,
701
//                                          @FloatRange(from = 0, to = 25, fromInclusive = false) final float radius) {
702
//        if (isEmptyBitmap(src)) return null;
703
//        RenderScript rs = null;
704
//        try {
705
//            rs = RenderScript.create(Utils.getApp());
706
//            rs.setMessageHandler(new RenderScript.RSMessageHandler());
707
//            Allocation input = Allocation.createFromBitmap(rs, src, Allocation.MipmapControl.MIPMAP_NONE, Allocation
708
//                    .USAGE_SCRIPT);
709
//            Allocation output = Allocation.createTyped(rs, input.getType());
710
//            ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
711
//            blurScript.setInput(input);
712
//            blurScript.setRadius(radius);
713
//            blurScript.forEach(output);
714
//            output.copyTo(src);
715
//        } finally {
716
//            if (rs != null) {
717
//                rs.destroy();
718
//            }
719
//        }
720
//        return src;
721
//    }
722
723
    /**
724
     * stack模糊图片
725
     *
726
     * @param src     源图片
727
     * @param radius  模糊半径
728
     * @param recycle 是否回收
729
     * @return stack模糊后的图片
730
     */
731
    public static Bitmap stackBlur(final Bitmap src, final int radius, final boolean recycle) {
732
        Bitmap ret;
733
        if (recycle) {
734
            ret = src;
735
        } else {
736
            ret = src.copy(src.getConfig(), true);
737
        }
738
739
        if (radius < 1) {
740
            return null;
741
        }
742
743
        int w = ret.getWidth();
744
        int h = ret.getHeight();
745
746
        int[] pix = new int[w * h];
747
        ret.getPixels(pix, 0, w, 0, 0, w, h);
748
749
        int wm = w - 1;
750
        int hm = h - 1;
751
        int wh = w * h;
752
        int div = radius + radius + 1;
753
754
        int r[] = new int[wh];
755
        int g[] = new int[wh];
756
        int b[] = new int[wh];
757
        int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
758
        int vmin[] = new int[Math.max(w, h)];
759
760
        int divsum = (div + 1) >> 1;
761
        divsum *= divsum;
762
        int dv[] = new int[256 * divsum];
763
        for (i = 0; i < 256 * divsum; i++) {
764
            dv[i] = (i / divsum);
765
        }
766
767
        yw = yi = 0;
768
769
        int[][] stack = new int[div][3];
770
        int stackpointer;
771
        int stackstart;
772
        int[] sir;
773
        int rbs;
774
        int r1 = radius + 1;
775
        int routsum, goutsum, boutsum;
776
        int rinsum, ginsum, binsum;
777
778
        for (y = 0; y < h; y++) {
779
            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
780
            for (i = -radius; i <= radius; i++) {
781
                p = pix[yi + Math.min(wm, Math.max(i, 0))];
782
                sir = stack[i + radius];
783
                sir[0] = (p & 0xff0000) >> 16;
784
                sir[1] = (p & 0x00ff00) >> 8;
785
                sir[2] = (p & 0x0000ff);
786
                rbs = r1 - Math.abs(i);
787
                rsum += sir[0] * rbs;
788
                gsum += sir[1] * rbs;
789
                bsum += sir[2] * rbs;
790
                if (i > 0) {
791
                    rinsum += sir[0];
792
                    ginsum += sir[1];
793
                    binsum += sir[2];
794
                } else {
795
                    routsum += sir[0];
796
                    goutsum += sir[1];
797
                    boutsum += sir[2];
798
                }
799
            }
800
            stackpointer = radius;
801
802
            for (x = 0; x < w; x++) {
803
804
                r[yi] = dv[rsum];
805
                g[yi] = dv[gsum];
806
                b[yi] = dv[bsum];
807
808
                rsum -= routsum;
809
                gsum -= goutsum;
810
                bsum -= boutsum;
811
812
                stackstart = stackpointer - radius + div;
813
                sir = stack[stackstart % div];
814
815
                routsum -= sir[0];
816
                goutsum -= sir[1];
817
                boutsum -= sir[2];
818
819
                if (y == 0) {
820
                    vmin[x] = Math.min(x + radius + 1, wm);
821
                }
822
                p = pix[yw + vmin[x]];
823
824
                sir[0] = (p & 0xff0000) >> 16;
825
                sir[1] = (p & 0x00ff00) >> 8;
826
                sir[2] = (p & 0x0000ff);
827
828
                rinsum += sir[0];
829
                ginsum += sir[1];
830
                binsum += sir[2];
831
832
                rsum += rinsum;
833
                gsum += ginsum;
834
                bsum += binsum;
835
836
                stackpointer = (stackpointer + 1) % div;
837
                sir = stack[(stackpointer) % div];
838
839
                routsum += sir[0];
840
                goutsum += sir[1];
841
                boutsum += sir[2];
842
843
                rinsum -= sir[0];
844
                ginsum -= sir[1];
845
                binsum -= sir[2];
846
847
                yi++;
848
            }
849
            yw += w;
850
        }
851
        for (x = 0; x < w; x++) {
852
            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
853
            yp = -radius * w;
854
            for (i = -radius; i <= radius; i++) {
855
                yi = Math.max(0, yp) + x;
856
857
                sir = stack[i + radius];
858
859
                sir[0] = r[yi];
860
                sir[1] = g[yi];
861
                sir[2] = b[yi];
862
863
                rbs = r1 - Math.abs(i);
864
865
                rsum += r[yi] * rbs;
866
                gsum += g[yi] * rbs;
867
                bsum += b[yi] * rbs;
868
869
                if (i > 0) {
870
                    rinsum += sir[0];
871
                    ginsum += sir[1];
872
                    binsum += sir[2];
873
                } else {
874
                    routsum += sir[0];
875
                    goutsum += sir[1];
876
                    boutsum += sir[2];
877
                }
878
879
                if (i < hm) {
880
                    yp += w;
881
                }
882
            }
883
            yi = x;
884
            stackpointer = radius;
885
            for (y = 0; y < h; y++) {
886
                // Preserve alpha channel: ( 0xff000000 & pix[yi] )
887
                pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
888
889
                rsum -= routsum;
890
                gsum -= goutsum;
891
                bsum -= boutsum;
892
893
                stackstart = stackpointer - radius + div;
894
                sir = stack[stackstart % div];
895
896
                routsum -= sir[0];
897
                goutsum -= sir[1];
898
                boutsum -= sir[2];
899
900
                if (x == 0) {
901
                    vmin[y] = Math.min(y + r1, hm) * w;
902
                }
903
                p = x + vmin[y];
904
905
                sir[0] = r[p];
906
                sir[1] = g[p];
907
                sir[2] = b[p];
908
909
                rinsum += sir[0];
910
                ginsum += sir[1];
911
                binsum += sir[2];
912
913
                rsum += rinsum;
914
                gsum += ginsum;
915
                bsum += binsum;
916
917
                stackpointer = (stackpointer + 1) % div;
918
                sir = stack[stackpointer];
919
920
                routsum += sir[0];
921
                goutsum += sir[1];
922
                boutsum += sir[2];
923
924
                rinsum -= sir[0];
925
                ginsum -= sir[1];
926
                binsum -= sir[2];
927
928
                yi += w;
929
            }
930
        }
931
        ret.setPixels(pix, 0, w, 0, 0, w, h);
932
        return ret;
933
    }
934
935
    /**
936
     * 添加颜色边框
937
     *
938
     * @param src         源图片
939
     * @param borderWidth 边框宽度
940
     * @param color       边框的颜色值
941
     * @return 带颜色边框图
942
     */
943
    public static Bitmap addFrame(final Bitmap src, final int borderWidth, final int color) {
944
        return addFrame(src, borderWidth, color, false);
945
    }
946
947
    /**
948
     * 添加颜色边框
949
     *
950
     * @param src         源图片
951
     * @param borderWidth 边框宽度
952
     * @param color       边框的颜色值
953
     * @param recycle     是否回收
954
     * @return 带颜色边框图
955
     */
956
    public static Bitmap addFrame(final Bitmap src, final int borderWidth, final int color, final boolean recycle) {
957
        if (isEmptyBitmap(src)) return null;
958
        int doubleBorder = borderWidth << 1;
959
        int newWidth = src.getWidth() + doubleBorder;
960
        int newHeight = src.getHeight() + doubleBorder;
961
        Bitmap ret = Bitmap.createBitmap(newWidth, newHeight, src.getConfig());
962
        Canvas canvas = new Canvas(ret);
963
        //noinspection SuspiciousNameCombination
964
        canvas.drawBitmap(src, borderWidth, borderWidth, null);
965
        Paint paint = new Paint();
966
        paint.setColor(color);
967
        paint.setStyle(Paint.Style.STROKE);
968
        // setStrokeWidth是居中画的,所以要两倍的宽度才能画,否则有一半的宽度是空的
969
        paint.setStrokeWidth(doubleBorder);
970
        Rect rect = new Rect(0, 0, newWidth, newHeight);
971
        canvas.drawRect(rect, paint);
972
        if (recycle && !src.isRecycled()) src.recycle();
973
        return ret;
974
    }
975
976
    /**
977
     * 添加倒影
978
     *
979
     * @param src              源图片的
980
     * @param reflectionHeight 倒影高度
981
     * @return 带倒影图片
982
     */
983
    public static Bitmap addReflection(final Bitmap src, final int reflectionHeight) {
984
        return addReflection(src, reflectionHeight, false);
985
    }
986
987
    /**
988
     * 添加倒影
989
     *
990
     * @param src              源图片的
991
     * @param reflectionHeight 倒影高度
992
     * @param recycle          是否回收
993
     * @return 带倒影图片
994
     */
995
    public static Bitmap addReflection(final Bitmap src, final int reflectionHeight, final boolean recycle) {
996
        if (isEmptyBitmap(src)) return null;
997
        // 原图与倒影之间的间距
998
        final int REFLECTION_GAP = 0;
999
        int srcWidth = src.getWidth();
1000
        int srcHeight = src.getHeight();
1001
        Matrix matrix = new Matrix();
1002
        matrix.preScale(1, -1);
1003
        Bitmap reflectionBitmap = Bitmap.createBitmap(src, 0, srcHeight - reflectionHeight,
1004
                srcWidth, reflectionHeight, matrix, false);
1005
        Bitmap ret = Bitmap.createBitmap(srcWidth, srcHeight + reflectionHeight, src.getConfig());
1006
        Canvas canvas = new Canvas(ret);
1007
        canvas.drawBitmap(src, 0, 0, null);
1008
        canvas.drawBitmap(reflectionBitmap, 0, srcHeight + REFLECTION_GAP, null);
1009
        Paint paint = new Paint();
1010
        paint.setAntiAlias(true);
1011
        LinearGradient shader = new LinearGradient(0, srcHeight,
1012
                0, ret.getHeight() + REFLECTION_GAP,
1013
                0x70FFFFFF, 0x00FFFFFF, Shader.TileMode.MIRROR);
1014
        paint.setShader(shader);
1015
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
1016
        canvas.drawRect(0, srcHeight + REFLECTION_GAP,
1017
                srcWidth, ret.getHeight(), paint);
1018
        if (!reflectionBitmap.isRecycled()) reflectionBitmap.recycle();
1019
        if (recycle && !src.isRecycled()) src.recycle();
1020
        return ret;
1021
    }
1022
1023
    /**
1024
     * 添加文字水印
1025
     *
1026
     * @param src      源图片
1027
     * @param content  水印文本
1028
     * @param textSize 水印字体大小
1029
     * @param color    水印字体颜色
1030
     * @param x        起始坐标x
1031
     * @param y        起始坐标y
1032
     * @return 带有文字水印的图片
1033
     */
1034
    public static Bitmap addTextWatermark(final Bitmap src,
1035
                                          final String content,
1036
                                          final int textSize,
1037
                                          final int color,
1038
                                          final float x,
1039
                                          final float y) {
1040
        return addTextWatermark(src, content, textSize, color, x, y, false);
1041
    }
1042
1043
    /**
1044
     * 添加文字水印
1045
     *
1046
     * @param src      源图片
1047
     * @param content  水印文本
1048
     * @param textSize 水印字体大小
1049
     * @param color    水印字体颜色
1050
     * @param x        起始坐标x
1051
     * @param y        起始坐标y
1052
     * @param recycle  是否回收
1053
     * @return 带有文字水印的图片
1054
     */
1055
    public static Bitmap addTextWatermark(final Bitmap src,
1056
                                          final String content,
1057
                                          final float textSize,
1058
                                          final int color,
1059
                                          final float x,
1060
                                          final float y,
1061
                                          final boolean recycle) {
1062
        if (isEmptyBitmap(src) || content == null) return null;
1063
        Bitmap ret = src.copy(src.getConfig(), true);
1064
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
1065
        Canvas canvas = new Canvas(ret);
1066
        paint.setColor(color);
1067
        paint.setTextSize(textSize);
1068
        Rect bounds = new Rect();
1069
        paint.getTextBounds(content, 0, content.length(), bounds);
1070
        canvas.drawText(content, x, y + textSize, paint);
1071
        if (recycle && !src.isRecycled()) src.recycle();
1072
        return ret;
1073
    }
1074
1075
    /**
1076
     * 添加图片水印
1077
     *
1078
     * @param src       源图片
1079
     * @param watermark 图片水印
1080
     * @param x         起始坐标x
1081
     * @param y         起始坐标y
1082
     * @param alpha     透明度
1083
     * @return 带有图片水印的图片
1084
     */
1085
    public static Bitmap addImageWatermark(final Bitmap src, final Bitmap watermark, final int x, final int y, final int alpha) {
1086
        return addImageWatermark(src, watermark, x, y, alpha, false);
1087
    }
1088
1089
    /**
1090
     * 添加图片水印
1091
     *
1092
     * @param src       源图片
1093
     * @param watermark 图片水印
1094
     * @param x         起始坐标x
1095
     * @param y         起始坐标y
1096
     * @param alpha     透明度
1097
     * @param recycle   是否回收
1098
     * @return 带有图片水印的图片
1099
     */
1100
    public static Bitmap addImageWatermark(final Bitmap src, final Bitmap watermark, final int x, final int y, final int alpha, final boolean recycle) {
1101
        if (isEmptyBitmap(src)) return null;
1102
        Bitmap ret = src.copy(src.getConfig(), true);
1103
        if (!isEmptyBitmap(watermark)) {
1104
            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
1105
            Canvas canvas = new Canvas(ret);
1106
            paint.setAlpha(alpha);
1107
            canvas.drawBitmap(watermark, x, y, paint);
1108
        }
1109
        if (recycle && !src.isRecycled()) src.recycle();
1110
        return ret;
1111
    }
1112
1113
    /**
1114
     * 转为alpha位图
1115
     *
1116
     * @param src 源图片
1117
     * @return alpha位图
1118
     */
1119
    public static Bitmap toAlpha(final Bitmap src) {
1120
        return toAlpha(src, false);
1121
    }
1122
1123
    /**
1124
     * 转为alpha位图
1125
     *
1126
     * @param src     源图片
1127
     * @param recycle 是否回收
1128
     * @return alpha位图
1129
     */
1130
    public static Bitmap toAlpha(final Bitmap src, final Boolean recycle) {
1131
        if (isEmptyBitmap(src)) return null;
1132
        Bitmap ret = src.extractAlpha();
1133
        if (recycle && !src.isRecycled()) src.recycle();
1134
        return ret;
1135
    }
1136
1137
    /**
1138
     * 转为灰度图片
1139
     *
1140
     * @param src 源图片
1141
     * @return 灰度图
1142
     */
1143
    public static Bitmap toGray(final Bitmap src) {
1144
        return toGray(src, false);
1145
    }
1146
1147
    /**
1148
     * 转为灰度图片
1149
     *
1150
     * @param src     源图片
1151
     * @param recycle 是否回收
1152
     * @return 灰度图
1153
     */
1154
    public static Bitmap toGray(final Bitmap src, final boolean recycle) {
1155
        if (isEmptyBitmap(src)) return null;
1156
        Bitmap grayBitmap = Bitmap.createBitmap(src.getWidth(),
1157
                src.getHeight(), Bitmap.Config.ARGB_8888);
1158
        Canvas canvas = new Canvas(grayBitmap);
1159
        Paint paint = new Paint();
1160
        ColorMatrix colorMatrix = new ColorMatrix();
1161
        colorMatrix.setSaturation(0);
1162
        ColorMatrixColorFilter colorMatrixColorFilter = new ColorMatrixColorFilter(colorMatrix);
1163
        paint.setColorFilter(colorMatrixColorFilter);
1164
        canvas.drawBitmap(src, 0, 0, paint);
1165
        if (recycle && !src.isRecycled()) src.recycle();
1166
        return grayBitmap;
1167
    }
1168
1169
    /**
1170
     * 保存图片
1171
     *
1172
     * @param src      源图片
1173
     * @param filePath 要保存到的文件路径
1174
     * @param format   格式
1175
     * @return {@code true}: 成功<br>{@code false}: 失败
1176
     */
1177
//    public static boolean save(final Bitmap src, final String filePath, final CompressFormat format) {
1178
//        return save(src, FileUtils.getFileByPath(filePath), format, false);
1179
//    }
1180
1181
    /**
1182
     * 保存图片
1183
     *
1184
     * @param src    源图片
1185
     * @param file   要保存到的文件
1186
     * @param format 格式
1187
     * @return {@code true}: 成功<br>{@code false}: 失败
1188
     */
1189
//    public static boolean save(final Bitmap src, final File file, final CompressFormat format) {
1190
//        return save(src, file, format, false);
1191
//    }
1192
1193
    /**
1194
     * 保存图片
1195
     *
1196
     * @param src      源图片
1197
     * @param filePath 要保存到的文件路径
1198
     * @param format   格式
1199
     * @param recycle  是否回收
1200
     * @return {@code true}: 成功<br>{@code false}: 失败
1201
     */
1202
//    public static boolean save(final Bitmap src, final String filePath, final CompressFormat format, final boolean recycle) {
1203
//        return save(src, FileUtils.getFileByPath(filePath), format, recycle);
1204
//    }
1205
1206
    /**
1207
     * 保存图片
1208
     *
1209
     * @param src     源图片
1210
     * @param file    要保存到的文件
1211
     * @param format  格式
1212
     * @param recycle 是否回收
1213
     * @return {@code true}: 成功<br>{@code false}: 失败
1214
     */
1215
//    public static boolean save(final Bitmap src, final File file, final CompressFormat format, final boolean recycle) {
1216
//        if (isEmptyBitmap(src) || !FileUtils.createOrExistsFile(file)) return false;
1217
//        System.out.println(src.getWidth() + ", " + src.getHeight());
1218
//        OutputStream os = null;
1219
//        boolean ret = false;
1220
//        try {
1221
//            os = new BufferedOutputStream(new FileOutputStream(file));
1222
//            ret = src.compress(format, 100, os);
1223
//            if (recycle && !src.isRecycled()) src.recycle();
1224
//        } catch (IOException e) {
1225
//            e.printStackTrace();
1226
//        } finally {
1227
//            CloseUtils.closeIO(os);
1228
//        }
1229
//        return ret;
1230
//    }
1231
1232
    /**
1233
     * 根据文件名判断文件是否为图片
1234
     *
1235
     * @param file  文件
1236
     * @return {@code true}: 是<br>{@code false}: 否
1237
     */
1238
    public static boolean isImage(final File file) {
1239
        return file != null && isImage(file.getPath());
1240
    }
1241
1242
    /**
1243
     * 根据文件名判断文件是否为图片
1244
     *
1245
     * @param filePath  文件路径
1246
     * @return {@code true}: 是<br>{@code false}: 否
1247
     */
1248
    public static boolean isImage(final String filePath) {
1249
        String path = filePath.toUpperCase();
1250
        return path.endsWith(".PNG") || path.endsWith(".JPG")
1251
                || path.endsWith(".JPEG") || path.endsWith(".BMP")
1252
                || path.endsWith(".GIF");
1253
    }
1254
1255
    /**
1256
     * 获取图片类型
1257
     *
1258
     * @param filePath 文件路径
1259
     * @return 图片类型
1260
     */
1261
//    public static String getImageType(final String filePath) {
1262
//        return getImageType(FileUtils.getFileByPath(filePath));
1263
//    }
1264
1265
    /**
1266
     * 获取图片类型
1267
     *
1268
     * @param file 文件
1269
     * @return 图片类型
1270
     */
1271
//    public static String getImageType(final File file) {
1272
//        if (file == null) return null;
1273
//        InputStream is = null;
1274
//        try {
1275
//            is = new FileInputStream(file);
1276
//            return getImageType(is);
1277
//        } catch (IOException e) {
1278
//            e.printStackTrace();
1279
//            return null;
1280
//        } finally {
1281
//            CloseUtils.closeIO(is);
1282
//        }
1283
//    }
1284
1285
    /**
1286
     * 流获取图片类型
1287
     *
1288
     * @param is 图片输入流
1289
     * @return 图片类型
1290
     */
1291
    public static String getImageType(final InputStream is) {
1292
        if (is == null) return null;
1293
        try {
1294
            byte[] bytes = new byte[8];
1295
            return is.read(bytes, 0, 8) != -1 ? getImageType(bytes) : null;
1296
        } catch (IOException e) {
1297
            e.printStackTrace();
1298
            return null;
1299
        }
1300
    }
1301
1302
    /**
1303
     * 获取图片类型
1304
     *
1305
     * @param bytes bitmap的前8字节
1306
     * @return 图片类型
1307
     */
1308
    public static String getImageType(final byte[] bytes) {
1309
        if (isJPEG(bytes)) return "JPEG";
1310
        if (isGIF(bytes)) return "GIF";
1311
        if (isPNG(bytes)) return "PNG";
1312
        if (isBMP(bytes)) return "BMP";
1313
        return null;
1314
    }
1315
1316
    private static boolean isJPEG(final byte[] b) {
1317
        return b.length >= 2
1318
                && (b[0] == (byte) 0xFF) && (b[1] == (byte) 0xD8);
1319
    }
1320
1321
    private static boolean isGIF(final byte[] b) {
1322
        return b.length >= 6
1323
                && b[0] == 'G' && b[1] == 'I'
1324
                && b[2] == 'F' && b[3] == '8'
1325
                && (b[4] == '7' || b[4] == '9') && b[5] == 'a';
1326
    }
1327
1328
    private static boolean isPNG(final byte[] b) {
1329
        return b.length >= 8
1330
                && (b[0] == (byte) 137 && b[1] == (byte) 80
1331
                && b[2] == (byte) 78 && b[3] == (byte) 71
1332
                && b[4] == (byte) 13 && b[5] == (byte) 10
1333
                && b[6] == (byte) 26 && b[7] == (byte) 10);
1334
    }
1335
1336
    private static boolean isBMP(final byte[] b) {
1337
        return b.length >= 2
1338
                && (b[0] == 0x42) && (b[1] == 0x4d);
1339
    }
1340
1341
    /**
1342
     * 判断bitmap对象是否为空
1343
     *
1344
     * @param src 源图片
1345
     * @return {@code true}: 是<br>{@code false}: 否
1346
     */
1347
    private static boolean isEmptyBitmap(final Bitmap src) {
1348
        return src == null || src.getWidth() == 0 || src.getHeight() == 0;
1349
    }
1350
1351
    ///////////////////////////////////////////////////////////////////////////
1352
    // 下方和压缩有关
1353
    ///////////////////////////////////////////////////////////////////////////
1354
1355
    /**
1356
     * 按缩放压缩
1357
     *
1358
     * @param src       源图片
1359
     * @param newWidth  新宽度
1360
     * @param newHeight 新高度
1361
     * @return 缩放压缩后的图片
1362
     */
1363
    public static Bitmap compressByScale(final Bitmap src, final int newWidth, final int newHeight) {
1364
        return scale(src, newWidth, newHeight, false);
1365
    }
1366
1367
    /**
1368
     * 按缩放压缩
1369
     *
1370
     * @param src       源图片
1371
     * @param newWidth  新宽度
1372
     * @param newHeight 新高度
1373
     * @param recycle   是否回收
1374
     * @return 缩放压缩后的图片
1375
     */
1376
    public static Bitmap compressByScale(final Bitmap src, final int newWidth, final int newHeight, final boolean recycle) {
1377
        return scale(src, newWidth, newHeight, recycle);
1378
    }
1379
1380
    /**
1381
     * 按缩放压缩
1382
     *
1383
     * @param src         源图片
1384
     * @param scaleWidth  缩放宽度倍数
1385
     * @param scaleHeight 缩放高度倍数
1386
     * @return 缩放压缩后的图片
1387
     */
1388
    public static Bitmap compressByScale(final Bitmap src, final float scaleWidth, final float scaleHeight) {
1389
        return scale(src, scaleWidth, scaleHeight, false);
1390
    }
1391
1392
    /**
1393
     * 按缩放压缩
1394
     *
1395
     * @param src         源图片
1396
     * @param scaleWidth  缩放宽度倍数
1397
     * @param scaleHeight 缩放高度倍数
1398
     * @param recycle     是否回收
1399
     * @return 缩放压缩后的图片
1400
     */
1401
    public static Bitmap compressByScale(final Bitmap src, final float scaleWidth, final float scaleHeight, final boolean recycle) {
1402
        return scale(src, scaleWidth, scaleHeight, recycle);
1403
    }
1404
1405
    /**
1406
     * 按质量压缩
1407
     *
1408
     * @param src     源图片
1409
     * @param quality 质量
1410
     * @return 质量压缩后的图片
1411
     */
1412
    public static Bitmap compressByQuality(final Bitmap src, @IntRange(from = 0, to = 100) final int quality) {
1413
        return compressByQuality(src, quality, false);
1414
    }
1415
1416
    /**
1417
     * 按质量压缩
1418
     *
1419
     * @param src     源图片
1420
     * @param quality 质量
1421
     * @param recycle 是否回收
1422
     * @return 质量压缩后的图片
1423
     */
1424
    public static Bitmap compressByQuality(final Bitmap src, @IntRange(from = 0, to = 100) final int quality, final boolean recycle) {
1425
        if (isEmptyBitmap(src)) return null;
1426
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
1427
        src.compress(CompressFormat.JPEG, quality, baos);
1428
        byte[] bytes = baos.toByteArray();
1429
        if (recycle && !src.isRecycled()) src.recycle();
1430
        return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
1431
    }
1432
1433
    /**
1434
     * 按质量压缩
1435
     *
1436
     * @param src         源图片
1437
     * @param maxByteSize 允许最大值字节数
1438
     * @return 质量压缩压缩过的图片
1439
     */
1440
    public static Bitmap compressByQuality(final Bitmap src, final long maxByteSize) {
1441
        return compressByQuality(src, maxByteSize, false);
1442
    }
1443
1444
    /**
1445
     * 按质量压缩
1446
     *
1447
     * @param src         源图片
1448
     * @param maxByteSize 允许最大值字节数
1449
     * @param recycle     是否回收
1450
     * @return 质量压缩压缩过的图片
1451
     */
1452
    public static Bitmap compressByQuality(final Bitmap src, final long maxByteSize, final boolean recycle) {
1453
        if (isEmptyBitmap(src) || maxByteSize <= 0) return null;
1454
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
1455
        int quality = 100;
1456
        src.compress(CompressFormat.JPEG, quality, baos);
1457
        while (baos.toByteArray().length > maxByteSize && quality > 0) {
1458
            baos.reset();
1459
            src.compress(CompressFormat.JPEG, quality -= 5, baos);
1460
        }
1461
        if (quality < 0) return null;
1462
        byte[] bytes = baos.toByteArray();
1463
        if (recycle && !src.isRecycled()) src.recycle();
1464
        return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
1465
    }
1466
1467
    /**
1468
     * 按采样大小压缩
1469
     *
1470
     * @param src        源图片
1471
     * @param sampleSize 采样率大小
1472
     * @return 按采样率压缩后的图片
1473
     */
1474
    public static Bitmap compressBySampleSize(final Bitmap src, final int sampleSize) {
1475
        return compressBySampleSize(src, sampleSize, false);
1476
    }
1477
1478
    /**
1479
     * 按采样大小压缩
1480
     *
1481
     * @param src        源图片
1482
     * @param sampleSize 采样率大小
1483
     * @param recycle    是否回收
1484
     * @return 按采样率压缩后的图片
1485
     */
1486
    public static Bitmap compressBySampleSize(final Bitmap src, final int sampleSize, final boolean recycle) {
1487
        if (isEmptyBitmap(src)) return null;
1488
        BitmapFactory.Options options = new BitmapFactory.Options();
1489
        options.inSampleSize = sampleSize;
1490
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
1491
        src.compress(CompressFormat.JPEG, 100, baos);
1492
        byte[] bytes = baos.toByteArray();
1493
        if (recycle && !src.isRecycled()) src.recycle();
1494
        return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);
1495
    }
1496
1497
    private static boolean isSpace(final String s) {
1498
        if (s == null) return true;
1499
        for (int i = 0, len = s.length(); i < len; ++i) {
1500
            if (!Character.isWhitespace(s.charAt(i))) {
1501
                return false;
1502
            }
1503
        }
1504
        return true;
1505
    }
1506
1507
    /**
1508
     * 读取照片exif信息中的旋转角度
1509
     *
1510
     * @param path 照片路径
1511
     * @return角度
1512
     */
1513
    public static int readPictureDegree(String path) {
1514
        int degree = 0;
1515
        try {
1516
            ExifInterface exifInterface = new ExifInterface(path);
1517
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
1518
            switch (orientation) {
1519
                case ExifInterface.ORIENTATION_ROTATE_90:
1520
                    degree = 90;
1521
                    break;
1522
                case ExifInterface.ORIENTATION_ROTATE_180:
1523
                    degree = 180;
1524
                    break;
1525
                case ExifInterface.ORIENTATION_ROTATE_270:
1526
                    degree = 270;
1527
                    break;
1528
            }
1529
        } catch (IOException e) {
1530
            e.printStackTrace();
1531
        }
1532
        return degree;
1533
    }
1534
1535
1536
    public static Bitmap toturn(Bitmap img) {
1537
        Matrix matrix = new Matrix();
1538
        matrix.postRotate(+90); /*翻转90度*/
1539
        int width = img.getWidth();
1540
        int height = img.getHeight();
1541
        img = Bitmap.createBitmap(img, 0, 0, width, height, matrix, true);
1542
        return img;
1543
    }
1544
1545
1546
}

+ 415 - 0
app/src/main/java/com/electric/chargingpile/view/xrichtext/RichTextEditor.java

@ -0,0 +1,415 @@
1
package com.electric.chargingpile.view.xrichtext;
2
3
import android.animation.LayoutTransition;
4
import android.content.Context;
5
import android.graphics.Bitmap;
6
import android.graphics.BitmapFactory;
7
import android.graphics.Matrix;
8
import android.media.ExifInterface;
9
import android.util.AttributeSet;
10
import android.util.Log;
11
import android.view.KeyEvent;
12
import android.view.LayoutInflater;
13
import android.view.View;
14
import android.view.ViewGroup;
15
import android.view.inputmethod.InputMethodManager;
16
import android.widget.EditText;
17
import android.widget.ImageView;
18
import android.widget.LinearLayout;
19
import android.widget.RelativeLayout;
20
import android.widget.ScrollView;
21
22
import com.bumptech.glide.Glide;
23
import com.bumptech.glide.request.RequestOptions;
24
import com.electric.chargingpile.R;
25
26
import java.io.IOException;
27
import java.util.ArrayList;
28
import java.util.List;
29
30
import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade;
31
32
/**
33
 * 可编辑富文本
34
 */
35
public class RichTextEditor extends ScrollView {
36
    private static final String TAG = "RichTextEditor";
37
    private static final int EDIT_PADDING = 10; // edittext常规padding是10dp
38
39
    private int viewTagIndex = 1; // 新生的view都会打一个tag,对每个view来说,这个tag是唯一的。
40
    private LinearLayout allLayout; // 这个是所有子view的容器,scrollView内部的唯一一个ViewGroup
41
    private LayoutInflater inflater;
42
    private OnKeyListener keyListener; // 所有EditText的软键盘监听器
43
    private OnClickListener btnListener; // 图片右上角红叉按钮监听器
44
    private OnFocusChangeListener focusListener; // 所有EditText的焦点监听listener
45
    private EditText lastFocusEdit; // 最近被聚焦的EditText
46
    private LayoutTransition mTransitioner; // 只在图片View添加或remove时,触发transition动画
47
    private int editNormalPadding = 0; //
48
    private int disappearingImageIndex = 0;
49
50
    public RichTextEditor(Context context) {
51
        this(context, null);
52
    }
53
54
    public RichTextEditor(Context context, AttributeSet attrs) {
55
        this(context, attrs, 0);
56
    }
57
58
    public RichTextEditor(Context context, AttributeSet attrs, int defStyleAttr) {
59
        super(context, attrs, defStyleAttr);
60
        inflater = LayoutInflater.from(context);
61
62
        // 1. 初始化allLayout
63
        allLayout = new LinearLayout(context);
64
        allLayout.setOrientation(LinearLayout.VERTICAL);
65
        //allLayout.setBackgroundColor(Color.WHITE);
66
        setupLayoutTransitions();
67
        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
68
                LayoutParams.WRAP_CONTENT);
69
        allLayout.setPadding(50, 15, 50, 15);//设置间距,防止生成图片时文字太靠边,不能用margin,否则有黑边
70
        addView(allLayout, layoutParams);
71
72
        // 2. 初始化键盘退格监听
73
        // 主要用来处理点击回删按钮时,view的一些列合并操作
74
        keyListener = new OnKeyListener() {
75
76
            @Override
77
            public boolean onKey(View v, int keyCode, KeyEvent event) {
78
                if (event.getAction() == KeyEvent.ACTION_DOWN
79
                        && event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
80
                    EditText edit = (EditText) v;
81
                    onBackspacePress(edit);
82
                }
83
                return false;
84
            }
85
        };
86
87
        // 3. 图片叉掉处理
88
        btnListener = new OnClickListener() {
89
90
            @Override
91
            public void onClick(View v) {
92
                RelativeLayout parentView = (RelativeLayout) v.getParent();
93
                onImageCloseClick(parentView);
94
            }
95
        };
96
97
        focusListener = new OnFocusChangeListener() {
98
99
            @Override
100
            public void onFocusChange(View v, boolean hasFocus) {
101
                if (hasFocus) {
102
                    lastFocusEdit = (EditText) v;
103
                }
104
            }
105
        };
106
107
        LinearLayout.LayoutParams firstEditParam = new LinearLayout.LayoutParams(
108
                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
109
        //editNormalPadding = dip2px(EDIT_PADDING);
110
        EditText firstEdit = createEditText("请填写问题相关描述信息(选填)", dip2px(context, EDIT_PADDING));
111
        allLayout.addView(firstEdit, firstEditParam);
112
        lastFocusEdit = firstEdit;
113
    }
114
115
    /**
116
     * 初始化transition动画
117
     */
118
    private void setupLayoutTransitions() {
119
        mTransitioner = new LayoutTransition();
120
        allLayout.setLayoutTransition(mTransitioner);
121
        mTransitioner.addTransitionListener(new LayoutTransition.TransitionListener() {
122
123
            @Override
124
            public void startTransition(LayoutTransition transition,
125
                                        ViewGroup container, View view, int transitionType) {
126
127
            }
128
129
            @Override
130
            public void endTransition(LayoutTransition transition,
131
                                      ViewGroup container, View view, int transitionType) {
132
                if (!transition.isRunning()
133
                        && transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
134
                    // transition动画结束,合并EditText
135
                    // mergeEditText();
136
                }
137
            }
138
        });
139
        mTransitioner.setDuration(300);
140
    }
141
142
    public int dip2px(Context context, float dipValue) {
143
        float m = context.getResources().getDisplayMetrics().density;
144
        return (int) (dipValue * m + 0.5f);
145
    }
146
147
    /**
148
     * 处理软键盘backSpace回退事件
149
     *
150
     * @param editTxt 光标所在的文本输入框
151
     */
152
    private void onBackspacePress(EditText editTxt) {
153
        int startSelection = editTxt.getSelectionStart();
154
        // 只有在光标已经顶到文本输入框的最前方,在判定是否删除之前的图片,或两个View合并
155
        if (startSelection == 0) {
156
            int editIndex = allLayout.indexOfChild(editTxt);
157
            View preView = allLayout.getChildAt(editIndex - 1); // 如果editIndex-1<0,
158
            // 则返回的是null
159
            if (null != preView) {
160
                if (preView instanceof RelativeLayout) {
161
                    // 光标EditText的上一个view对应的是图片
162
                    onImageCloseClick(preView);
163
                } else if (preView instanceof EditText) {
164
                    // 光标EditText的上一个view对应的还是文本框EditText
165
                    String str1 = editTxt.getText().toString();
166
                    EditText preEdit = (EditText) preView;
167
                    String str2 = preEdit.getText().toString();
168
169
                    allLayout.removeView(editTxt);
170
171
                    // 文本合并
172
                    preEdit.setText(str2 + str1);
173
                    preEdit.requestFocus();
174
                    preEdit.setSelection(str2.length(), str2.length());
175
                    lastFocusEdit = preEdit;
176
                }
177
            }
178
        }
179
    }
180
181
    /**
182
     * 处理图片叉掉的点击事件
183
     *
184
     * @param view 整个image对应的relativeLayout view
185
     * @type 删除类型 0代表backspace删除 1代表按红叉按钮删除
186
     */
187
    private void onImageCloseClick(View view) {
188
        disappearingImageIndex = allLayout.indexOfChild(view);
189
        Log.e(TAG, "onImageCloseClick: " + disappearingImageIndex);
190
        //删除文件夹里的图片
191
        List<EditData> dataList = buildEditData();
192
        EditData editData = dataList.get(disappearingImageIndex);
193
        //Log.i("", "editData: "+editData);
194
        if (editData.imagePath != null) {
195
            SDCardUtil.deleteFile(editData.imagePath);
196
        }
197
198
        allLayout.removeView(view);
199
    }
200
201
    public void clearAllLayout() {
202
        allLayout.removeAllViews();
203
    }
204
205
    public int getLastIndex() {
206
        int lastEditIndex = allLayout.getChildCount();
207
        return lastEditIndex;
208
    }
209
210
    /**
211
     * 生成文本输入框
212
     */
213
    public EditText createEditText(String hint, int paddingTop) {
214
        EditText editText = (EditText) inflater.inflate(R.layout.rich_edittext, null);
215
        editText.setOnKeyListener(keyListener);
216
        editText.setTag(viewTagIndex++);
217
        editText.setPadding(editNormalPadding, paddingTop, editNormalPadding, paddingTop);
218
        editText.setHint(hint);
219
        editText.setOnFocusChangeListener(focusListener);
220
        return editText;
221
    }
222
223
    /**
224
     * 生成图片View
225
     */
226
    private RelativeLayout createImageLayout() {
227
        RelativeLayout layout = (RelativeLayout) inflater.inflate(
228
                R.layout.edit_imageview, null);
229
        layout.setTag(viewTagIndex++);
230
        View closeView = layout.findViewById(R.id.image_close);
231
        //closeView.setVisibility(GONE);
232
        closeView.setTag(layout.getTag());
233
        closeView.setOnClickListener(btnListener);
234
        return layout;
235
    }
236
237
    /**
238
     * 根据绝对路径添加view
239
     *
240
     * @param imagePath
241
     */
242
    public void insertImage(String imagePath, int width) {
243
        Bitmap bmp = getScaledBitmap(imagePath, width);
244
        insertImage(bmp, imagePath);
245
    }
246
247
    /**
248
     * 插入一张图片
249
     */
250
    public void insertImage(Bitmap bitmap, String imagePath) {
251
        String lastEditStr = lastFocusEdit.getText().toString();
252
        int cursorIndex = lastFocusEdit.getSelectionStart();
253
        String editStr1 = lastEditStr.substring(0, cursorIndex).trim();
254
        int lastEditIndex = allLayout.indexOfChild(lastFocusEdit);
255
256
        if (lastEditStr.length() == 0 || editStr1.length() == 0) {
257
            // 如果EditText为空,或者光标已经顶在了editText的最前面,则直接插入图片,并且EditText下移即可
258
            addImageViewAtIndex(lastEditIndex, imagePath);
259
        } else {
260
            // 如果EditText非空且光标不在最顶端,则需要添加新的imageView和EditText
261
            lastFocusEdit.setText(editStr1);
262
            String editStr2 = lastEditStr.substring(cursorIndex).trim();
263
            if (editStr2.length() == 0) {
264
                editStr2 = " ";
265
            }
266
            if (allLayout.getChildCount() - 1 == lastEditIndex) {
267
                addEditTextAtIndex(lastEditIndex + 1, editStr2);
268
            }
269
270
            addImageViewAtIndex(lastEditIndex + 1, imagePath);
271
            lastFocusEdit.requestFocus();
272
            lastFocusEdit.setSelection(editStr1.length(), editStr1.length());//TODO
273
        }
274
        hideKeyBoard();
275
    }
276
277
    /**
278
     * 隐藏小键盘
279
     */
280
    public void hideKeyBoard() {
281
        InputMethodManager imm = (InputMethodManager) getContext()
282
                .getSystemService(Context.INPUT_METHOD_SERVICE);
283
        imm.hideSoftInputFromWindow(lastFocusEdit.getWindowToken(), 0);
284
    }
285
286
    /**
287
     * 在特定位置插入EditText
288
     *
289
     * @param index   位置
290
     * @param editStr EditText显示的文字
291
     */
292
    public void addEditTextAtIndex(final int index, CharSequence editStr) {
293
        EditText editText2 = createEditText("", EDIT_PADDING);
294
        editText2.setText(editStr);
295
        editText2.setOnFocusChangeListener(focusListener);
296
297
        allLayout.addView(editText2, index);
298
    }
299
300
    /**
301
     * 在特定位置添加ImageView
302
     */
303
    public void addImageViewAtIndex(final int index, String imagePath) {
304
        final RelativeLayout imageLayout = createImageLayout();
305
        DataImageView imageView = (DataImageView) imageLayout.findViewById(R.id.edit_imageView);
306
        Log.e(TAG, "addImageViewAtIndex: " + imagePath);
307
308
309
        if (readPictureDegree(imagePath) != 0) {
310
            Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
311
            Log.e(TAG, "addImageViewAtIndex: " + "!!!!!!!!!!");
312
            bitmap = toturn(bitmap);
313
            Log.e(TAG, "addImageViewAtIndex: " + "--------");
314
            imageView.setImageBitmap(bitmap);
315
        } else {
316
            RequestOptions options = new RequestOptions().centerCrop();
317
            Glide.with(getContext()).load(imagePath).apply(options).transition(withCrossFade()).into(imageView);
318
        }
319
320
321
        imageView.setAbsolutePath(imagePath);//保留这句,后面保存数据会用
322
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);//裁剪剧中
323
324
        // 调整imageView的高度,根据宽度来调整高度
325
        Bitmap bmp = BitmapFactory.decodeFile(imagePath);
326
        int imageHeight = 500;
327
        if (bmp != null) {
328
            imageHeight = allLayout.getWidth() * bmp.getHeight() / bmp.getWidth();
329
            bmp.recycle();
330
        }
331
        // TODO: 17/3/1 调整图片高度,这里是否有必要,如果出现微博长图,可能会很难看
332
        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
333
                LayoutParams.MATCH_PARENT, imageHeight);//设置图片固定高度
334
        lp.bottomMargin = 10;
335
        imageView.setLayoutParams(lp);
336
337
        allLayout.addView(imageLayout, index);
338
    }
339
340
    /**
341
     * 根据view的宽度,动态缩放bitmap尺寸
342
     *
343
     * @param width view的宽度
344
     */
345
    public Bitmap getScaledBitmap(String filePath, int width) {
346
        BitmapFactory.Options options = new BitmapFactory.Options();
347
        options.inJustDecodeBounds = true;
348
        BitmapFactory.decodeFile(filePath, options);
349
        int sampleSize = options.outWidth > width ? options.outWidth / width
350
                + 1 : 1;
351
        options.inJustDecodeBounds = false;
352
        options.inSampleSize = sampleSize;
353
        return BitmapFactory.decodeFile(filePath, options);
354
    }
355
356
    /**
357
     * 对外提供的接口, 生成编辑数据上传
358
     */
359
    public List<EditData> buildEditData() {
360
        List<EditData> dataList = new ArrayList<EditData>();
361
        int num = allLayout.getChildCount();
362
        for (int index = 0; index < num; index++) {
363
            View itemView = allLayout.getChildAt(index);
364
            EditData itemData = new EditData();
365
            if (itemView instanceof EditText) {
366
                EditText item = (EditText) itemView;
367
                itemData.inputStr = item.getText().toString();
368
            } else if (itemView instanceof RelativeLayout) {
369
                DataImageView item = (DataImageView) itemView.findViewById(R.id.edit_imageView);
370
                itemData.imagePath = item.getAbsolutePath();
371
            }
372
            dataList.add(itemData);
373
        }
374
375
        return dataList;
376
    }
377
378
    public class EditData {
379
        public String inputStr;
380
        public String imagePath;
381
    }
382
383
    public static int readPictureDegree(String path) {
384
        int degree = 0;
385
        try {
386
            ExifInterface exifInterface = new ExifInterface(path);
387
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
388
            switch (orientation) {
389
                case ExifInterface.ORIENTATION_ROTATE_90:
390
                    degree = 90;
391
                    break;
392
                case ExifInterface.ORIENTATION_ROTATE_180:
393
                    degree = 180;
394
                    break;
395
                case ExifInterface.ORIENTATION_ROTATE_270:
396
                    degree = 270;
397
                    break;
398
            }
399
        } catch (IOException e) {
400
            e.printStackTrace();
401
        }
402
        Log.e(TAG, "readPictureDegree: degree=" + degree);
403
        return degree;
404
    }
405
406
407
    public static Bitmap toturn(Bitmap img) {
408
        Matrix matrix = new Matrix();
409
        matrix.postRotate(+90); /*翻转90度*/
410
        int width = img.getWidth();
411
        int height = img.getHeight();
412
        img = Bitmap.createBitmap(img, 0, 0, width, height, matrix, true);
413
        return img;
414
    }
415
}

+ 412 - 0
app/src/main/java/com/electric/chargingpile/view/xrichtext/RichTextEditorForA.java

@ -0,0 +1,412 @@
1
package com.electric.chargingpile.view.xrichtext;
2
3
import android.animation.LayoutTransition;
4
import android.content.Context;
5
import android.graphics.Bitmap;
6
import android.graphics.BitmapFactory;
7
import android.graphics.Matrix;
8
import android.media.ExifInterface;
9
import android.util.AttributeSet;
10
import android.util.Log;
11
import android.view.KeyEvent;
12
import android.view.LayoutInflater;
13
import android.view.View;
14
import android.view.ViewGroup;
15
import android.view.inputmethod.InputMethodManager;
16
import android.widget.EditText;
17
import android.widget.ImageView;
18
import android.widget.LinearLayout;
19
import android.widget.RelativeLayout;
20
import android.widget.ScrollView;
21
22
import com.bumptech.glide.Glide;
23
import com.bumptech.glide.request.RequestOptions;
24
import com.electric.chargingpile.R;
25
26
import java.io.IOException;
27
import java.util.ArrayList;
28
import java.util.List;
29
30
import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade;
31
32
/**
33
 * 可编辑富文本
34
 */
35
public class RichTextEditorForA extends ScrollView {
36
    private static final String TAG = "RichTextEditorForA";
37
    private static final int EDIT_PADDING = 10; // edittext常规padding是10dp
38
39
    private int viewTagIndex = 1; // 新生的view都会打一个tag,对每个view来说,这个tag是唯一的。
40
    private LinearLayout allLayout; // 这个是所有子view的容器,scrollView内部的唯一一个ViewGroup
41
    private LayoutInflater inflater;
42
    private OnKeyListener keyListener; // 所有EditText的软键盘监听器
43
    private OnClickListener btnListener; // 图片右上角红叉按钮监听器
44
    private OnFocusChangeListener focusListener; // 所有EditText的焦点监听listener
45
    private EditText lastFocusEdit; // 最近被聚焦的EditText
46
    private LayoutTransition mTransitioner; // 只在图片View添加或remove时,触发transition动画
47
    private int editNormalPadding = 0; //
48
    private int disappearingImageIndex = 0;
49
50
    public RichTextEditorForA(Context context) {
51
        this(context, null);
52
    }
53
54
    public RichTextEditorForA(Context context, AttributeSet attrs) {
55
        this(context, attrs, 0);
56
    }
57
58
    public RichTextEditorForA(Context context, AttributeSet attrs, int defStyleAttr) {
59
        super(context, attrs, defStyleAttr);
60
        inflater = LayoutInflater.from(context);
61
62
        // 1. 初始化allLayout
63
        allLayout = new LinearLayout(context);
64
        allLayout.setOrientation(LinearLayout.VERTICAL);
65
        //allLayout.setBackgroundColor(Color.WHITE);
66
        setupLayoutTransitions();
67
        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
68
                LayoutParams.WRAP_CONTENT);
69
        allLayout.setPadding(50, 15, 50, 15);//设置间距,防止生成图片时文字太靠边,不能用margin,否则有黑边
70
        addView(allLayout, layoutParams);
71
72
        // 2. 初始化键盘退格监听
73
        // 主要用来处理点击回删按钮时,view的一些列合并操作
74
        keyListener = new OnKeyListener() {
75
76
            @Override
77
            public boolean onKey(View v, int keyCode, KeyEvent event) {
78
                if (event.getAction() == KeyEvent.ACTION_DOWN
79
                        && event.getKeyCode() == KeyEvent.KEYCODE_DEL) {
80
                    EditText edit = (EditText) v;
81
                    onBackspacePress(edit);
82
                }
83
                return false;
84
            }
85
        };
86
87
        // 3. 图片叉掉处理
88
        btnListener = new OnClickListener() {
89
90
            @Override
91
            public void onClick(View v) {
92
                RelativeLayout parentView = (RelativeLayout) v.getParent();
93
                onImageCloseClick(parentView);
94
            }
95
        };
96
97
        focusListener = new OnFocusChangeListener() {
98
99
            @Override
100
            public void onFocusChange(View v, boolean hasFocus) {
101
                if (hasFocus) {
102
                    lastFocusEdit = (EditText) v;
103
                }
104
            }
105
        };
106
107
        LinearLayout.LayoutParams firstEditParam = new LinearLayout.LayoutParams(
108
                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
109
        //editNormalPadding = dip2px(EDIT_PADDING);
110
        EditText firstEdit = createEditText("请填写问题相关的回答", dip2px(context, EDIT_PADDING));
111
        allLayout.addView(firstEdit, firstEditParam);
112
        lastFocusEdit = firstEdit;
113
    }
114
115
    /**
116
     * 初始化transition动画
117
     */
118
    private void setupLayoutTransitions() {
119
        mTransitioner = new LayoutTransition();
120
        allLayout.setLayoutTransition(mTransitioner);
121
        mTransitioner.addTransitionListener(new LayoutTransition.TransitionListener() {
122
123
            @Override
124
            public void startTransition(LayoutTransition transition,
125
                                        ViewGroup container, View view, int transitionType) {
126
127
            }
128
129
            @Override
130
            public void endTransition(LayoutTransition transition,
131
                                      ViewGroup container, View view, int transitionType) {
132
                if (!transition.isRunning()
133
                        && transitionType == LayoutTransition.CHANGE_DISAPPEARING) {
134
                    // transition动画结束,合并EditText
135
                    // mergeEditText();
136
                }
137
            }
138
        });
139
        mTransitioner.setDuration(300);
140
    }
141
142
    public int dip2px(Context context, float dipValue) {
143
        float m = context.getResources().getDisplayMetrics().density;
144
        return (int) (dipValue * m + 0.5f);
145
    }
146
147
    /**
148
     * 处理软键盘backSpace回退事件
149
     *
150
     * @param editTxt 光标所在的文本输入框
151
     */
152
    private void onBackspacePress(EditText editTxt) {
153
        int startSelection = editTxt.getSelectionStart();
154
        // 只有在光标已经顶到文本输入框的最前方,在判定是否删除之前的图片,或两个View合并
155
        if (startSelection == 0) {
156
            int editIndex = allLayout.indexOfChild(editTxt);
157
            View preView = allLayout.getChildAt(editIndex - 1); // 如果editIndex-1<0,
158
            // 则返回的是null
159
            if (null != preView) {
160
                if (preView instanceof RelativeLayout) {
161
                    // 光标EditText的上一个view对应的是图片
162
                    onImageCloseClick(preView);
163
                } else if (preView instanceof EditText) {
164
                    // 光标EditText的上一个view对应的还是文本框EditText
165
                    String str1 = editTxt.getText().toString();
166
                    EditText preEdit = (EditText) preView;
167
                    String str2 = preEdit.getText().toString();
168
169
                    allLayout.removeView(editTxt);
170
171
                    // 文本合并
172
                    preEdit.setText(str2 + str1);
173
                    preEdit.requestFocus();
174
                    preEdit.setSelection(str2.length(), str2.length());
175
                    lastFocusEdit = preEdit;
176
                }
177
            }
178
        }
179
    }
180
181
    /**
182
     * 处理图片叉掉的点击事件
183
     *
184
     * @param view 整个image对应的relativeLayout view
185
     * @type 删除类型 0代表backspace删除 1代表按红叉按钮删除
186
     */
187
    private void onImageCloseClick(View view) {
188
        disappearingImageIndex = allLayout.indexOfChild(view);
189
        Log.e(TAG, "onImageCloseClick: " + disappearingImageIndex);
190
        //删除文件夹里的图片
191
        List<EditData> dataList = buildEditData();
192
        EditData editData = dataList.get(disappearingImageIndex);
193
        //Log.i("", "editData: "+editData);
194
        if (editData.imagePath != null) {
195
            SDCardUtil.deleteFile(editData.imagePath);
196
        }
197
198
        allLayout.removeView(view);
199
    }
200
201
    public void clearAllLayout() {
202
        allLayout.removeAllViews();
203
    }
204
205
    public int getLastIndex() {
206
        int lastEditIndex = allLayout.getChildCount();
207
        return lastEditIndex;
208
    }
209
210
    /**
211
     * 生成文本输入框
212
     */
213
    public EditText createEditText(String hint, int paddingTop) {
214
        EditText editText = (EditText) inflater.inflate(R.layout.rich_edittext, null);
215
        editText.setOnKeyListener(keyListener);
216
        editText.setTag(viewTagIndex++);
217
        editText.setPadding(editNormalPadding, paddingTop, editNormalPadding, paddingTop);
218
        editText.setHint(hint);
219
        editText.setOnFocusChangeListener(focusListener);
220
        return editText;
221
    }
222
223
    /**
224
     * 生成图片View
225
     */
226
    private RelativeLayout createImageLayout() {
227
        RelativeLayout layout = (RelativeLayout) inflater.inflate(
228
                R.layout.edit_imageview, null);
229
        layout.setTag(viewTagIndex++);
230
        View closeView = layout.findViewById(R.id.image_close);
231
        //closeView.setVisibility(GONE);
232
        closeView.setTag(layout.getTag());
233
        closeView.setOnClickListener(btnListener);
234
        return layout;
235
    }
236
237
    /**
238
     * 根据绝对路径添加view
239
     *
240
     * @param imagePath
241
     */
242
    public void insertImage(String imagePath, int width) {
243
        Bitmap bmp = getScaledBitmap(imagePath, width);
244
        insertImage(bmp, imagePath);
245
    }
246
247
    /**
248
     * 插入一张图片
249
     */
250
    public void insertImage(Bitmap bitmap, String imagePath) {
251
        String lastEditStr = lastFocusEdit.getText().toString();
252
        int cursorIndex = lastFocusEdit.getSelectionStart();
253
        String editStr1 = lastEditStr.substring(0, cursorIndex).trim();
254
        int lastEditIndex = allLayout.indexOfChild(lastFocusEdit);
255
256
        if (lastEditStr.length() == 0 || editStr1.length() == 0) {
257
            // 如果EditText为空,或者光标已经顶在了editText的最前面,则直接插入图片,并且EditText下移即可
258
            addImageViewAtIndex(lastEditIndex, imagePath);
259
        } else {
260
            // 如果EditText非空且光标不在最顶端,则需要添加新的imageView和EditText
261
            lastFocusEdit.setText(editStr1);
262
            String editStr2 = lastEditStr.substring(cursorIndex).trim();
263
            if (editStr2.length() == 0) {
264
                editStr2 = " ";
265
            }
266
            if (allLayout.getChildCount() - 1 == lastEditIndex) {
267
                addEditTextAtIndex(lastEditIndex + 1, editStr2);
268
            }
269
270
            addImageViewAtIndex(lastEditIndex + 1, imagePath);
271
            lastFocusEdit.requestFocus();
272
            lastFocusEdit.setSelection(editStr1.length(), editStr1.length());//TODO
273
        }
274
        hideKeyBoard();
275
    }
276
277
    /**
278
     * 隐藏小键盘
279
     */
280
    public void hideKeyBoard() {
281
        InputMethodManager imm = (InputMethodManager) getContext()
282
                .getSystemService(Context.INPUT_METHOD_SERVICE);
283
        imm.hideSoftInputFromWindow(lastFocusEdit.getWindowToken(), 0);
284
    }
285
286
    /**
287
     * 在特定位置插入EditText
288
     *
289
     * @param index   位置
290
     * @param editStr EditText显示的文字
291
     */
292
    public void addEditTextAtIndex(final int index, CharSequence editStr) {
293
        EditText editText2 = createEditText("", EDIT_PADDING);
294
        editText2.setText(editStr);
295
        editText2.setOnFocusChangeListener(focusListener);
296
297
        allLayout.addView(editText2, index);
298
    }
299
300
    /**
301
     * 在特定位置添加ImageView
302
     */
303
    public void addImageViewAtIndex(final int index, String imagePath) {
304
        final RelativeLayout imageLayout = createImageLayout();
305
        DataImageView imageView = (DataImageView) imageLayout.findViewById(R.id.edit_imageView);
306
307
308
        if (readPictureDegree(imagePath) != 0) {
309
            Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
310
            Log.e(TAG, "addImageViewAtIndex: " + "!!!!!!!!!!");
311
            bitmap = toturn(bitmap);
312
            Log.e(TAG, "addImageViewAtIndex: " + "--------");
313
            imageView.setImageBitmap(bitmap);
314
        } else {
315
            RequestOptions options = new RequestOptions().centerCrop();
316
            Glide.with(getContext()).load(imagePath).apply(options).transition(withCrossFade()).into(imageView);
317
        }
318
        imageView.setAbsolutePath(imagePath);//保留这句,后面保存数据会用
319
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);//裁剪剧中
320
321
        // 调整imageView的高度,根据宽度来调整高度
322
        Bitmap bmp = BitmapFactory.decodeFile(imagePath);
323
        int imageHeight = 500;
324
        if (bmp != null) {
325
            imageHeight = allLayout.getWidth() * bmp.getHeight() / bmp.getWidth();
326
            bmp.recycle();
327
        }
328
        // TODO: 17/3/1 调整图片高度,这里是否有必要,如果出现微博长图,可能会很难看
329
        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
330
                LayoutParams.MATCH_PARENT, imageHeight);//设置图片固定高度
331
        lp.bottomMargin = 10;
332
        imageView.setLayoutParams(lp);
333
334
        allLayout.addView(imageLayout, index);
335
    }
336
337
    /**
338
     * 根据view的宽度,动态缩放bitmap尺寸
339
     *
340
     * @param width view的宽度
341
     */
342
    public Bitmap getScaledBitmap(String filePath, int width) {
343
        BitmapFactory.Options options = new BitmapFactory.Options();
344
        options.inJustDecodeBounds = true;
345
        BitmapFactory.decodeFile(filePath, options);
346
        int sampleSize = options.outWidth > width ? options.outWidth / width
347
                + 1 : 1;
348
        options.inJustDecodeBounds = false;
349
        options.inSampleSize = sampleSize;
350
        return BitmapFactory.decodeFile(filePath, options);
351
    }
352
353
    /**
354
     * 对外提供的接口, 生成编辑数据上传
355
     */
356
    public List<EditData> buildEditData() {
357
        List<EditData> dataList = new ArrayList<EditData>();
358
        int num = allLayout.getChildCount();
359
        for (int index = 0; index < num; index++) {
360
            View itemView = allLayout.getChildAt(index);
361
            EditData itemData = new EditData();
362
            if (itemView instanceof EditText) {
363
                EditText item = (EditText) itemView;
364
                itemData.inputStr = item.getText().toString();
365
            } else if (itemView instanceof RelativeLayout) {
366
                DataImageView item = (DataImageView) itemView.findViewById(R.id.edit_imageView);
367
                itemData.imagePath = item.getAbsolutePath();
368
            }
369
            dataList.add(itemData);
370
        }
371
372
        return dataList;
373
    }
374
375
    public class EditData {
376
        public String inputStr;
377
        public String imagePath;
378
    }
379
380
    public static int readPictureDegree(String path) {
381
        int degree = 0;
382
        try {
383
            ExifInterface exifInterface = new ExifInterface(path);
384
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
385
            switch (orientation) {
386
                case ExifInterface.ORIENTATION_ROTATE_90:
387
                    degree = 90;
388
                    break;
389
                case ExifInterface.ORIENTATION_ROTATE_180:
390
                    degree = 180;
391
                    break;
392
                case ExifInterface.ORIENTATION_ROTATE_270:
393
                    degree = 270;
394
                    break;
395
            }
396
        } catch (IOException e) {
397
            e.printStackTrace();
398
        }
399
        Log.e(TAG, "readPictureDegree: degree=" + degree);
400
        return degree;
401
    }
402
403
404
    public static Bitmap toturn(Bitmap img) {
405
        Matrix matrix = new Matrix();
406
        matrix.postRotate(+90); /*翻转90度*/
407
        int width = img.getWidth();
408
        int height = img.getHeight();
409
        img = Bitmap.createBitmap(img, 0, 0, width, height, matrix, true);
410
        return img;
411
    }
412
}

+ 179 - 0
app/src/main/java/com/electric/chargingpile/view/xrichtext/RichTextView.java

@ -0,0 +1,179 @@
1
package com.electric.chargingpile.view.xrichtext;
2
3
import android.content.Context;
4
import android.graphics.Bitmap;
5
import android.graphics.BitmapFactory;
6
import android.util.AttributeSet;
7
import android.view.LayoutInflater;
8
import android.view.View;
9
import android.widget.ImageView;
10
import android.widget.LinearLayout;
11
import android.widget.RelativeLayout;
12
import android.widget.ScrollView;
13
import android.widget.TextView;
14
15
import com.bumptech.glide.Glide;
16
import com.bumptech.glide.request.RequestOptions;
17
import com.electric.chargingpile.R;
18
19
/**
20
 * Created by sendtion on 2016/6/24.
21
 * 显示富文本
22
 */
23
public class RichTextView extends ScrollView {
24
    private static final String TAG = "RichTextView";
25
    private static final int EDIT_PADDING = 3; // edittext常规padding是10dp
26
27
    private int viewTagIndex = 1; // 新生的view都会打一个tag,对每个view来说,这个tag是唯一的。
28
    private LinearLayout allLayout; // 这个是所有子view的容器,scrollView内部的唯一一个ViewGroup
29
    private LayoutInflater inflater;
30
    private int editNormalPadding = 0; //
31
32
    public RichTextView(Context context) {
33
        this(context, null);
34
    }
35
36
    public RichTextView(Context context, AttributeSet attrs) {
37
        this(context, attrs, 0);
38
    }
39
40
    public RichTextView(Context context, AttributeSet attrs, int defStyleAttr) {
41
        super(context, attrs, defStyleAttr);
42
        inflater = LayoutInflater.from(context);
43
44
        // 1. 初始化allLayout
45
        allLayout = new LinearLayout(context);
46
        allLayout.setOrientation(LinearLayout.VERTICAL);
47
        //allLayout.setBackgroundColor(Color.WHITE);//去掉背景
48
        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
49
                LayoutParams.WRAP_CONTENT);
50
        allLayout.setPadding(50, 15, 50, 15);//设置间距,防止生成图片时文字太靠边
51
        addView(allLayout, layoutParams);
52
53
        LinearLayout.LayoutParams firstEditParam = new LinearLayout.LayoutParams(
54
                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
55
        //editNormalPadding = dip2px(EDIT_PADDING);
56
        TextView firstText = createTextView("没有内容", dip2px(context, EDIT_PADDING));
57
        allLayout.addView(firstText, firstEditParam);
58
    }
59
60
    public int dip2px(Context context, float dipValue) {
61
        float m = context.getResources().getDisplayMetrics().density;
62
        return (int) (dipValue * m + 0.5f);
63
    }
64
65
    /**
66
     * 清除所有的view
67
     */
68
    public void clearAllLayout() {
69
        allLayout.removeAllViews();
70
    }
71
72
    /**
73
     * 获得最后一个子view的位置
74
     *
75
     * @return
76
     */
77
    public int getLastIndex() {
78
        int lastEditIndex = allLayout.getChildCount();
79
        return lastEditIndex;
80
    }
81
82
    /**
83
     * 生成文本输入框
84
     */
85
    public TextView createTextView(String hint, int paddingTop) {
86
        TextView textView = (TextView) inflater.inflate(R.layout.rich_textview, null);
87
        textView.setTag(viewTagIndex++);
88
        textView.setPadding(editNormalPadding, paddingTop, editNormalPadding, paddingTop);
89
        textView.setHint(hint);
90
        return textView;
91
    }
92
93
    /**
94
     * 生成图片View
95
     */
96
    private RelativeLayout createImageLayout() {
97
        RelativeLayout layout = (RelativeLayout) inflater.inflate(
98
                R.layout.edit_imageview, null);
99
        layout.setTag(viewTagIndex++);
100
        View closeView = layout.findViewById(R.id.image_close);
101
        closeView.setVisibility(GONE);
102
        return layout;
103
    }
104
105
    /**
106
     * 在特定位置插入EditText
107
     *
108
     * @param index   位置
109
     * @param editStr EditText显示的文字
110
     */
111
    public void addTextViewAtIndex(final int index, CharSequence editStr) {
112
        TextView textView = createTextView("", EDIT_PADDING);
113
        textView.setText(editStr);
114
115
        allLayout.addView(textView, index);
116
    }
117
118
    /**
119
     * 在特定位置添加ImageView
120
     */
121
    public void addImageViewAtIndex(final int index, String imagePath) {
122
        String width, height;
123
        String[] strarray = imagePath.split("\\&");
124
        final String path = strarray[0];
125
        width = strarray[1];
126
        if (width.contains(".")) {
127
            width = width.substring(0, width.indexOf("."));
128
        }
129
        height = strarray[2];
130
        if (height.contains(".")) {
131
            height = height.substring(0, height.indexOf("."));
132
        }
133
134
//        Bitmap bmp = BitmapFactory.decodeFile(imagePath);
135
136
        final RelativeLayout imageLayout = createImageLayout();
137
        DataImageView imageView = (DataImageView) imageLayout.findViewById(R.id.edit_imageView);
138
        RequestOptions options = new RequestOptions().centerCrop();
139
        Glide.with(getContext()).load(imagePath).apply(options).into(imageView);
140
        //imageView.setImageBitmap(bmp);//这里改用Glide加载图片
141
        //imageView.setBitmap(bmp);//这句去掉,保留下面的图片地址即可,优化图片占用
142
//        imageView.setAbsolutePath(imagePath);//保留这句,后面保存数据会用
143
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);//裁剪剧中
144
145
        // 调整imageView的高度
146
        int imageHeight = 500;
147
        int img_width = Integer.parseInt(width);
148
        int img_height = Integer.parseInt(height);
149
        if (width != null) {
150
            imageHeight = allLayout.getWidth() * img_height / img_width;
151
            // 使用之后,还是回收掉吧
152
//            bmp.recycle();
153
        }
154
//        Log.e(TAG, "addImageViewAtIndex_imageHeight: "+imageHeight );
155
        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
156
                LayoutParams.MATCH_PARENT, imageHeight);
157
        lp.bottomMargin = 6;
158
        imageView.setLayoutParams(lp);
159
160
        allLayout.addView(imageLayout, index);
161
    }
162
163
    /**
164
     * 根据view的宽度,动态缩放bitmap尺寸
165
     *
166
     * @param width view的宽度
167
     */
168
    public Bitmap getScaledBitmap(String filePath, int width) {
169
        BitmapFactory.Options options = new BitmapFactory.Options();
170
        options.inJustDecodeBounds = true;
171
        BitmapFactory.decodeFile(filePath, options);
172
        int sampleSize = options.outWidth > width ? options.outWidth / width
173
                + 1 : 1;
174
        options.inJustDecodeBounds = false;
175
        options.inSampleSize = sampleSize;
176
        return BitmapFactory.decodeFile(filePath, options);
177
    }
178
179
}

+ 131 - 0
app/src/main/java/com/electric/chargingpile/view/xrichtext/SDCardUtil.java

@ -0,0 +1,131 @@
1
package com.electric.chargingpile.view.xrichtext;
2
3
import android.content.ContentResolver;
4
import android.content.Context;
5
import android.database.Cursor;
6
import android.graphics.Bitmap;
7
import android.net.Uri;
8
import android.os.Environment;
9
import android.provider.MediaStore;
10
11
import java.io.File;
12
import java.io.FileNotFoundException;
13
import java.io.FileOutputStream;
14
import java.io.IOException;
15
16
public class SDCardUtil {
17
    public static String SDCardRoot = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator;
18
19
    /**
20
     * 检查是否存在SDCard
21
     *
22
     * @return
23
     */
24
    public static boolean hasSdcard() {
25
        String state = Environment.getExternalStorageState();
26
        if (state.equals(Environment.MEDIA_MOUNTED)) {
27
            return true;
28
        } else {
29
            return false;
30
        }
31
    }
32
33
    /**
34
     * 获得文章图片保存路径
35
     *
36
     * @return
37
     */
38
    public static String getPictureDir() {
39
        String imageCacheUrl = SDCardRoot + "XRichText" + File.separator;
40
        File file = new File(imageCacheUrl);
41
        if (!file.exists())
42
            file.mkdir();  //如果不存在则创建
43
        return imageCacheUrl;
44
    }
45
46
    /**
47
     * 图片保存到SD卡
48
     *
49
     * @param bitmap
50
     * @return
51
     */
52
    public static String saveToSdCard(Bitmap bitmap) {
53
        String imageUrl = getPictureDir() + System.currentTimeMillis() + "-.jpeg";
54
        File file = new File(imageUrl);
55
        try {
56
            FileOutputStream out = new FileOutputStream(file);
57
            if (bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out)) {
58
                out.flush();
59
                out.close();
60
            }
61
        } catch (FileNotFoundException e) {
62
            e.printStackTrace();
63
        } catch (IOException e) {
64
            e.printStackTrace();
65
        }
66
        return file.getAbsolutePath();
67
    }
68
69
    /**
70
     * 保存到指定路径,笔记中插入图片
71
     *
72
     * @param bitmap
73
     * @param path
74
     * @return
75
     */
76
    public static String saveToSdCard(Bitmap bitmap, String path) {
77
        File file = new File(path);
78
        try {
79
            FileOutputStream out = new FileOutputStream(file);
80
            if (bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out)) {
81
                out.flush();
82
                out.close();
83
            }
84
        } catch (FileNotFoundException e) {
85
            e.printStackTrace();
86
        } catch (IOException e) {
87
            e.printStackTrace();
88
        }
89
        //System.out.println("文件保存路径:"+ file.getAbsolutePath());
90
        return file.getAbsolutePath();
91
    }
92
93
    /**
94
     * 删除文件
95
     **/
96
    public static void deleteFile(String filePath) {
97
        File file = new File(filePath);
98
        if (file.isFile() && file.exists())
99
            file.delete(); // 删除文件
100
    }
101
102
    /**
103
     * 根据Uri获取图片文件的绝对路径
104
     */
105
    public static String getFilePathByUri(Context context, final Uri uri) {
106
        if (null == uri) {
107
            return null;
108
        }
109
        final String scheme = uri.getScheme();
110
        String data = null;
111
        if (scheme == null) {
112
            data = uri.getPath();
113
        } else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
114
            data = uri.getPath();
115
        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
116
            Cursor cursor = context.getContentResolver().query(uri,
117
                    new String[]{MediaStore.Images.ImageColumns.DATA}, null, null, null);
118
            if (null != cursor) {
119
                if (cursor.moveToFirst()) {
120
                    int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
121
                    if (index > -1) {
122
                        data = cursor.getString(index);
123
                    }
124
                }
125
                cursor.close();
126
            }
127
        }
128
        return data;
129
    }
130
131
}

+ 24 - 0
app/src/main/res/layout/edit_imageview.xml

@ -0,0 +1,24 @@
1
<?xml version="1.0" encoding="utf-8"?>
2
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
    android:layout_width="match_parent"
4
    android:layout_height="wrap_content">
5
6
    <com.electric.chargingpile.view.xrichtext.DataImageView
7
        android:id="@+id/edit_imageView"
8
        android:layout_width="match_parent"
9
        android:layout_height="wrap_content"
10
        android:scaleType="fitXY" />
11
12
    <ImageView
13
        android:id="@+id/image_close"
14
        android:layout_width="50dp"
15
        android:layout_height="50dp"
16
        android:layout_alignParentRight="true"
17
        android:paddingLeft="20dp"
18
        android:paddingTop="5dp"
19
        android:paddingRight="5dp"
20
        android:paddingBottom="20dp"
21
        android:scaleType="fitXY"
22
        android:src="@drawable/icon_close" />
23
24
</RelativeLayout>

+ 9 - 0
app/src/main/res/layout/rich_edittext.xml

@ -0,0 +1,9 @@
1
<?xml version="1.0" encoding="utf-8"?>
2
<com.electric.chargingpile.view.xrichtext.DeletableEditText xmlns:android="http://schemas.android.com/apk/res/android"
3
    android:layout_width="match_parent"
4
    android:layout_height="wrap_content"
5
    android:background="@null"
6
    android:cursorVisible="true"
7
    android:lineSpacingExtra="8dp"
8
    android:textColor="#616161"
9
    android:textSize="16sp" />

+ 10 - 0
app/src/main/res/layout/rich_textview.xml

@ -0,0 +1,10 @@
1
<?xml version="1.0" encoding="utf-8"?>
2
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
3
    android:layout_width="match_parent"
4
    android:layout_height="wrap_content"
5
    android:background="@null"
6
    android:cursorVisible="true"
7
    android:lineSpacingExtra="8dp"
8
    android:textIsSelectable="true"
9
    android:textSize="16sp"
10
    android:textColor="#616161" />